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 24120850ba..549aab4823 100644 --- a/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala +++ b/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala @@ -25,7 +25,7 @@ import org.bitcoins.core.api.node.{ NodeApi, NodeType } -import org.bitcoins.core.util.{NetworkUtil, TimeUtil} +import org.bitcoins.core.util.TimeUtil import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte import org.bitcoins.dlc.node.DLCNode import org.bitcoins.dlc.node.config.DLCNodeAppConfig @@ -35,7 +35,6 @@ import org.bitcoins.feeprovider.MempoolSpaceTarget.HourFeeTarget import org.bitcoins.feeprovider._ import org.bitcoins.node._ import org.bitcoins.node.config.NodeAppConfig -import org.bitcoins.node.models.Peer import org.bitcoins.rpc.BitcoindException.InWarmUp import org.bitcoins.rpc.client.common.BitcoindRpcClient import org.bitcoins.rpc.config.{BitcoindRpcAppConfig, ZmqConfig} @@ -112,25 +111,13 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit def startBitcoinSBackend(): Future[Unit] = { logger.info(s"startBitcoinSBackend()") val start = System.currentTimeMillis() - if (nodeConf.peers.isEmpty) { - throw new IllegalArgumentException( - "No peers specified, unable to start node") - } - - val peerSockets = { - nodeConf.peers.map( - NetworkUtil.parseInetSocketAddress(_, nodeConf.network.port) - ) - } - - val peers = peerSockets.map(Peer.fromSocket(_, nodeConf.socks5ProxyParams)) //run chain work migration val chainApiF = runChainWorkCalc( serverArgParser.forceChainWorkRecalc || chainConf.forceRecalcChainWork) //get a node that isn't started - val nodeF = nodeConf.createNode(peers)(chainConf, system) + val nodeF = nodeConf.createNode()(chainConf, system) val feeProvider = getFeeProviderOrElse( MempoolSpaceProvider(HourFeeTarget, 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 new file mode 100644 index 0000000000..0c3b2526db --- /dev/null +++ b/core-test/src/test/scala/org/bitcoins/core/util/NetworkUtilTest.scala @@ -0,0 +1,16 @@ +package org.bitcoins.core.util + +import scodec.bits.ByteVector + +class NetworkUtilTest extends BitcoinSUtilTest { + "NetworkUtil" must "convert torV3 pubkey to correct .onion address and vice versa" in { + val pubkey = ByteVector.fromValidHex( + "98908ec971ad17171365865a249c420d04a66f103f973a62d8404ce2f4af1ee2") + val address = + "tcii5slrvulroe3fqzncjhccbuckm3yqh6ltuywyibgof5fpd3rpycyd.onion" + val addressFromKey = NetworkUtil.parseUnresolvedInetSocketAddress(pubkey) + val pubkeyFromAddress = ByteVector(NetworkUtil.torV3AddressToBytes(address)) + assert(address == addressFromKey) + assert(pubkey == pubkeyFromAddress) + } +} 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 dc5f249f06..c26d38525c 100644 --- a/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala +++ b/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala @@ -75,7 +75,8 @@ sealed abstract class MainNet extends BitcoinNetwork { "seed.btc.petertodd.org", "seed.bitcoin.jonasschnelli.ch", "seed.bitcoin.sprovoost.nl", - "dnsseed.emzy.de" + "dnsseed.emzy.de", + "seed.bitcoin.wiz.biz" ) } 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 cf67526bea..0777b9f9f3 100644 --- a/core/src/main/scala/org/bitcoins/core/util/NetworkUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/util/NetworkUtil.scala @@ -1,5 +1,9 @@ package org.bitcoins.core.util +import org.bitcoins.core.p2p.AddrV2Message +import org.bitcoins.crypto.CryptoUtil +import scodec.bits.ByteVector + import java.net._ import scala.annotation.tailrec import scala.util.{Failure, Random, Success, Try} @@ -17,6 +21,58 @@ abstract class NetworkUtil { InetSocketAddress.createUnresolved(uri.getHost, port) } + /** Parses IPV4,IPV6 ad TorV3 address bytes to string address */ + def parseInetSocketAddress( + address: ByteVector, + port: Int): InetSocketAddress = { + val uri: URI = { + address.size match { + case AddrV2Message.IPV4_ADDR_LENGTH => + val hostAddress = + InetAddress.getByAddress(address.toArray).getHostAddress + new URI("tcp://" + hostAddress) + case AddrV2Message.IPV6_ADDR_LENGTH => + val hostAddress = + InetAddress.getByAddress(address.toArray).getHostAddress + new URI(s"tcp://[$hostAddress]") + case AddrV2Message.TOR_V3_ADDR_LENGTH => + val hostAddress = parseUnresolvedInetSocketAddress(address) + new URI("tcp://" + hostAddress) + case unknownSize => + sys.error( + s"Attempted to parse InetSocketAddress with unknown size, got=${unknownSize}") + } + } + InetSocketAddress.createUnresolved(uri.getHost, port) + } + + // AddrV2 messages give pubkey bytes for TorV3 addresses and in config files addresses are as strings like + // dfghj...vbnm.onion hence such conversions to and from bytes to string is needed + + /** Parses TorV3 address bytes (pubkey) to string address */ + def parseUnresolvedInetSocketAddress(bytes: ByteVector): String = { + val version = BigInt(0x03).toByteArray + val pubkey = bytes.toArray + val checksum = CryptoUtil + .sha3_256(ByteVector(".onion checksum".getBytes ++ pubkey ++ version)) + .bytes + val address = + ByteVector( + pubkey ++ checksum.take(2).toArray ++ version).toBase32 + ".onion" + address.toLowerCase + } + + /** converts a string TorV3 address to pubkey bytes */ + def torV3AddressToBytes(address: String): Array[Byte] = { + val encoded = address.substring(0, address.indexOf('.')).toUpperCase + val decoded = ByteVector.fromBase32(encoded) match { + case Some(value) => value.toArray + case None => + throw new IllegalArgumentException("Invalid TorV3 onion address") + } + decoded.slice(0, decoded.length - 3) + } + def isLocalhost(hostName: String): Boolean = { hostName == "127.0.0.0" || hostName == "localhost" } diff --git a/crypto-test/.js/src/test/scala/org/bitcoins/crypto/HashingTest.scala b/crypto-test/.js/src/test/scala/org/bitcoins/crypto/HashingTest.scala index 5ceedb2a6a..27c816613c 100644 --- a/crypto-test/.js/src/test/scala/org/bitcoins/crypto/HashingTest.scala +++ b/crypto-test/.js/src/test/scala/org/bitcoins/crypto/HashingTest.scala @@ -5,23 +5,23 @@ import scodec.bits.ByteVector class HashingTest extends BitcoinSCryptoTest { private lazy val lines = Vector( - // rnd,sha1(rnd),sha256(rnd),ripeMd160(rnd),sha256Hash160(rnd),hmac(rnd,sha256) - "41dc440cf30c42cb17b935d3d8451b0c1e2a8ad9a529637228df5ca31a10c0a2,b600f58e73defdbb68650078f39760ba1bcfb391,4eb2b43a30cca0aebdefec2f6a30abb56a1f6d9b0462d252184dc5209c62d5d0,ddb6092b1103067c609b35bec4177abf5dfc9f5c,304d0d0762ec66b44764a11b0d02e234b1d75721,36d248dc8a9825ac48c32fe4ebf0b4dd8ee450c226f05dc8b8cfac62dbcc11a89bc00ab3942bc5ca74a7f189bff04fe9541b749a7670e9dcf36e3bdb37cd6e01", - "a361ef0fdc98778bd5c6f6c50a6300f560a88644029a623294091d2b3d0e22d7,7cb911a6852779261cc151410691bd408b23ba1d,d63c99b1abffc915ba9e35fdc5763304839d981dc25c106bdd90a8bdc4eb6f13,6003b2e364b11f2737c7fb4cb190fdd55783f76b,a4f38c39eab8afe5f2e63d1a89d0c365c96cc7a7,87c59c1c9535043a3c3ecdec25776613f198ae4707675c129a1ed8d217aac20f7d07ce4c84e6cfa833ee7d3e52b3673730b900e6ca7075185d1ecce473110447", - "35659ae4880ae74deda82a5d3b77ba8fc4adff84e1c46fa67955338bc7346977,e379fb92c9500d410818bd95796a87f662f1fd76,904a2128262e055f68896150e1b1da93849bda2054e5e6f6f8db11214a1b6855,a63e15d313afef12927f38924a97927ac3e61b8b,0c2109858080cad92ec93e883998b6048b671112,7bdd176479a379bb9447e5f7646cd0be210977b593d6a71fbdbe545a282b4fb9e22b6ec5d0afa62045fe96074b91544755f9c28ee0af368ae34165e5487d65d2", - "e3c54af8504a7f0d69f8f9c9b29c5d15fc861821547f285bb70d2850ce08efe9,a93c7e60aa08e08919c9085641ff1a7cd3400613,1325fb6c0029b128b0fdf37d014e3739aea56fc670756e335a2ce34fe08c2574,d5409d92add4c4f7fad2ae8eea100e19e2f1e66f,90dcb2f658418089a0d41abb7f012f2531f860a0,911a7b19f7f0f145921002ed3830d46045041e786cbea13c7f77066ed8a03d56ddaa2db987358f6a4c713fddd07570647fd80ea072da309a60758c305137d4a8", - "8283f8f51b5045ef414e462ebb5c9573950ec0162578df73d0f5490febac5a97,40ebb9af58651c51135641278884217f23f14993,540ed853ed97664d7ea82e663d2480076d1b81088a5ef405465871c8df3d1b9f,4c69787f663f188fbcee4b0d9a737083e018ac08,137b3fb7855dc321348e03c458ecc18daedf0f95,5172f81bbabd00b9c81654826dba9e527b5a1c553b9c2c92b7b59b420d5b8064c2fd3f9e8107ec3a07298f712de10a126d348d2bb6dac21aa397a665a1ee787d", - "6286477a8da8d7b6f2fc9080d5e7a4091b1d506ee2dc4f81740b0f54f438537d,aeded4ba719eb6fed787d34b8064402082db7a4d,3df54218915767977bdf2bcde8b45a711caa460c3baa2448f91bc13731e6ea3d,946d3624e583fef1b46bdb8c24155d62083c0b47,839cff76a9b045f49a0b7c44f34d8561dc442870,280245f199d155794032fb4ea90f22c38de688bfb4e43c66507994610d01676b0c05eb1d531fe4cb628fee5ff00b863feec037088e128c0d4e875816c9a4b6bd", - "47a8bb983cfc0387769dd6b80b8674c0531545c31cef0feff5c1113326003510,025c7f81895c1cd8e92c79a61a11b4b900eaf475,da19d198af8bcb060b07a8825f6898ac821b002b0e5da574cab2753bee430f8a,22292f488c729250acf0d2f7147fd6b2e6a808db,da91c4f8751060450782a9b023f6f5f4f2a0ee9f,aaebe082b58dce13087555d9ada0ec6c965acd39a014d47ad9f43700a8f36e466c5117165b4d585cc5bc5b295d9bbd6dcc8d27cce4a1c563ed1cfe1353186b79", - "8a329193ab14c37b397d749d1c254d9c5a962248cd2ad48460fb7cf659e89f52,ff4090d399bbb8e3220bc57ed13c6a0c44c79ea5,20460d4766c94a72ddef09c83f5eea9545af7826a446539c1a07291f6cdc5af4,eaf846e713cf63704cf1d80fd415265f4b5d6586,d45c9dc61b959c3548fe5c2de3781714d1dcf9f7,e5e62e56726480551da0b88de1657676979f3f5e6a028b3a0c91a186495060ebf5e4cab2c71675f36bd4b86c6ab8a1ee850eaffd93c28828504ae023783f6005", - "96c37689f01bd39b6f163fbf4b1025653ea196f0abdb8a5dcd8cbc76c78f8cf5,f7edf6a546b5c7023ae146ac1ef58256f0578b73,34957be30df1b91070c9b39e086b31906e295574d315eaf2e91c6b45a292bb84,84795b00f8405a6ca0fab024991f34187a1be0c1,2367689553879bbcea1ba7608eb1905fb8230565,98bc48d3da9fcb8723b5e37ae30a8aa54a411eede7a9e5220c9ae849cbd591577991922b8995ef34704618b23f1961770c9f31ebe346ca6089da391c96c6a11d", - "7eff84aeca24260baa06b61394bdec8b760a0c6558dd1748d91d6f492e0779b7,1c182efc13f2468d880372f4809d5a5e7011dfbf,13d1c9c1d3ac10cc78c43a2f0724a6a2e06adf5844a4ab45ff4779af1f15029d,8ce4f2abb9775f7e3cea0fa75238ab75cf6908e3,d3e2938a69fdce888260003f6f1702e9d3392ab0,4569f2282b016fee5b583390e709dd285eb09b7510bbe092f37e5fef581a78b42729eb9f46088d1d52a00f2f57d1ffd48ab64b5c0dfc38d01bf2c793c977fcfc", - "c7acfcf801519b59c4750b06d6d55b1915f3a0317859685dd2ae337a6065d4bb,384c59c208e92c46e4fb8bcea9e286181ee4f956,4853fbb9eafeb0bfe2d717ad34973ea979413874e97d92d7a85c16a8fb61626e,e45f80b6cd0533e8b6f9a974b17c20244812e0fe,d531970c5f1ca7d0772513b32e8b75fa837c27fd,fc7946c37e09c86ce48e704f162e96c06cd227df7813dcc910fb56793a8cd5b0f205207292f6c7d34aeddeae80d3a6243409f2d4bd11e0f4eba5e6711df77586", - "b53e7fb86d09133c5d1bfccae6a16652d26376784ec97995c9173f8d4d9151bc,69a8d04118b7f4e5c49a877ea2a1e6d9bdcc6dc5,33cb2e45fe278f822c9f8f0b0f6ca7c0aa84e588237a70e0870607756bdb18e0,f17ef3913819472407b45b9bf2bf454b4185bfe7,75cd9d71a818ccfc234c80cd89b6b52b898530bc,008892ec410fcc7197049a9967738edff5abeef1e29eb03a2b3f1939433f16ce284a9d3be887b3b1500161a38a617e8e467b4564bb6d030f617fc996d3a26dd2", - "7125adb44be6dc3bea98c348fc546b92371e99b4294d753c3a2c408447057a48,06fed168e3f0a8928d56c847364caeaf63c11f34,721e34ca27da076c1e18b51ffbf1f2921a431f55e83f85c4cbe679d5e081c120,023445e83064df92dcd60478cd68ea45f032d5c0,d0e99a8e4a7ba80bcc861b6dc81c29547dfd7dae,a485d3f5f22d70dae68176b76df8f8173adae876dcae8e93c5156277204a507484a50cc25b40e967ed75c4eaf29cda8e97ab8b05f72fa30a28e11ed9a30c6f7a", - "34ab9bc63b31a019e59af803cd9365500ed01e36e5d8e166d7fa22a3dd06a4b2,495804100e19df440a1026e016c3a55800064bed,203f617d00fada67c5d5f48736793d79d3b75633e8977d531a035b51df696853,4278ed1405c4d61d35bf2dbd8b0ad17cf8eb2de8,23656338b7894db5ca7c5804e91a128cf0d17acf,4ab854a2ce4f7a2ac71fb0b84b88f960cc0fd7467b9a6e298243b0117e8d38525876608fa403d43bceb2aee43abebac670db6e74a2f346cb1a254aa942cc1fbd", - "93dc29da56fac0a611c8c5014bc61a6c3861ae9def571818664c7e44b25a954d,ceb1b9394c434c5a1648112477c5f674ed4430ca,f3a1d0c012317a4802aa52ae17c03e6bb8f769d35c909af8c0dbab16fe238d79,31c690c105e778b5941492cdffa5a817adc14202,ac6975f571f6e961c3db6ac29cfc7e975b2aaa09,f2f758a0e28f40d2b13a590d57875295668f12725a1536b513b19f59b65f88f885229ef424f8b226ee5b53749097ca70aa8b6dbb3650779074775239c652b70c", - "f6372c5a3c6957b655d56167a4e723fc0eefdd3abf1857b2c7d797a0be0e4b0e,960b962cea70b57c7edc4f137261f94829957a3b,70eeaa3dc29f434da194e23bb5eb1001e9012bab15bec0fb9532c63f022c19a8,80f5a9119a99ef6bc04a1944f256fc8176216ad2,d535e38f334aa06538ea644849b80972a7fe6c6f,ac08b0031b5026157997b5c4a5f60df1c8afd39c5d7691033c72d65e4fa06312b48dd0cf46dd350188563c957ddabdb4b06ed2e9b4be2babcf640825358b555e" + // rnd,sha1(rnd),sha256(rnd),ripeMd160(rnd),sha256Hash160(rnd),hmac(rnd,sha256),sha3_256(rnd) + "41dc440cf30c42cb17b935d3d8451b0c1e2a8ad9a529637228df5ca31a10c0a2,b600f58e73defdbb68650078f39760ba1bcfb391,4eb2b43a30cca0aebdefec2f6a30abb56a1f6d9b0462d252184dc5209c62d5d0,ddb6092b1103067c609b35bec4177abf5dfc9f5c,304d0d0762ec66b44764a11b0d02e234b1d75721,36d248dc8a9825ac48c32fe4ebf0b4dd8ee450c226f05dc8b8cfac62dbcc11a89bc00ab3942bc5ca74a7f189bff04fe9541b749a7670e9dcf36e3bdb37cd6e01,870d8f928cc97f37b6e0845f9f8bde004f24a12ee36cc5c5408a8dc67eb9d051", + "a361ef0fdc98778bd5c6f6c50a6300f560a88644029a623294091d2b3d0e22d7,7cb911a6852779261cc151410691bd408b23ba1d,d63c99b1abffc915ba9e35fdc5763304839d981dc25c106bdd90a8bdc4eb6f13,6003b2e364b11f2737c7fb4cb190fdd55783f76b,a4f38c39eab8afe5f2e63d1a89d0c365c96cc7a7,87c59c1c9535043a3c3ecdec25776613f198ae4707675c129a1ed8d217aac20f7d07ce4c84e6cfa833ee7d3e52b3673730b900e6ca7075185d1ecce473110447,48d322b5b8c781bd027686f503682e2efc37f621bb5fef14ddfad9329f97bbbb", + "35659ae4880ae74deda82a5d3b77ba8fc4adff84e1c46fa67955338bc7346977,e379fb92c9500d410818bd95796a87f662f1fd76,904a2128262e055f68896150e1b1da93849bda2054e5e6f6f8db11214a1b6855,a63e15d313afef12927f38924a97927ac3e61b8b,0c2109858080cad92ec93e883998b6048b671112,7bdd176479a379bb9447e5f7646cd0be210977b593d6a71fbdbe545a282b4fb9e22b6ec5d0afa62045fe96074b91544755f9c28ee0af368ae34165e5487d65d2,d34318f7c0ae01caaebca717a6388cae96e3f8c506acd3f152d5619893d4defb", + "e3c54af8504a7f0d69f8f9c9b29c5d15fc861821547f285bb70d2850ce08efe9,a93c7e60aa08e08919c9085641ff1a7cd3400613,1325fb6c0029b128b0fdf37d014e3739aea56fc670756e335a2ce34fe08c2574,d5409d92add4c4f7fad2ae8eea100e19e2f1e66f,90dcb2f658418089a0d41abb7f012f2531f860a0,911a7b19f7f0f145921002ed3830d46045041e786cbea13c7f77066ed8a03d56ddaa2db987358f6a4c713fddd07570647fd80ea072da309a60758c305137d4a8,1b9a19ea9447d58fa980091d04e20b9f9b4999b54b415cc522089bfe664a6319", + "8283f8f51b5045ef414e462ebb5c9573950ec0162578df73d0f5490febac5a97,40ebb9af58651c51135641278884217f23f14993,540ed853ed97664d7ea82e663d2480076d1b81088a5ef405465871c8df3d1b9f,4c69787f663f188fbcee4b0d9a737083e018ac08,137b3fb7855dc321348e03c458ecc18daedf0f95,5172f81bbabd00b9c81654826dba9e527b5a1c553b9c2c92b7b59b420d5b8064c2fd3f9e8107ec3a07298f712de10a126d348d2bb6dac21aa397a665a1ee787d,eb4080b54011e5cd852d20b933412a1615f1d6fce96bb00af4d47b70b95f6b64", + "6286477a8da8d7b6f2fc9080d5e7a4091b1d506ee2dc4f81740b0f54f438537d,aeded4ba719eb6fed787d34b8064402082db7a4d,3df54218915767977bdf2bcde8b45a711caa460c3baa2448f91bc13731e6ea3d,946d3624e583fef1b46bdb8c24155d62083c0b47,839cff76a9b045f49a0b7c44f34d8561dc442870,280245f199d155794032fb4ea90f22c38de688bfb4e43c66507994610d01676b0c05eb1d531fe4cb628fee5ff00b863feec037088e128c0d4e875816c9a4b6bd,1d50401d65343f79ef63368043a0beba4171b86ef1991ec2b0be54b0f2e3f70a", + "47a8bb983cfc0387769dd6b80b8674c0531545c31cef0feff5c1113326003510,025c7f81895c1cd8e92c79a61a11b4b900eaf475,da19d198af8bcb060b07a8825f6898ac821b002b0e5da574cab2753bee430f8a,22292f488c729250acf0d2f7147fd6b2e6a808db,da91c4f8751060450782a9b023f6f5f4f2a0ee9f,aaebe082b58dce13087555d9ada0ec6c965acd39a014d47ad9f43700a8f36e466c5117165b4d585cc5bc5b295d9bbd6dcc8d27cce4a1c563ed1cfe1353186b79,73057ed727c4b004c3f3af867c667bff8b6671271a689c8ca99dd82f098e341b", + "8a329193ab14c37b397d749d1c254d9c5a962248cd2ad48460fb7cf659e89f52,ff4090d399bbb8e3220bc57ed13c6a0c44c79ea5,20460d4766c94a72ddef09c83f5eea9545af7826a446539c1a07291f6cdc5af4,eaf846e713cf63704cf1d80fd415265f4b5d6586,d45c9dc61b959c3548fe5c2de3781714d1dcf9f7,e5e62e56726480551da0b88de1657676979f3f5e6a028b3a0c91a186495060ebf5e4cab2c71675f36bd4b86c6ab8a1ee850eaffd93c28828504ae023783f6005,fcf3adea6f02d4f2bc2ef3f0d2be9f190524c80d65a1d97f1f358e5048938229", + "96c37689f01bd39b6f163fbf4b1025653ea196f0abdb8a5dcd8cbc76c78f8cf5,f7edf6a546b5c7023ae146ac1ef58256f0578b73,34957be30df1b91070c9b39e086b31906e295574d315eaf2e91c6b45a292bb84,84795b00f8405a6ca0fab024991f34187a1be0c1,2367689553879bbcea1ba7608eb1905fb8230565,98bc48d3da9fcb8723b5e37ae30a8aa54a411eede7a9e5220c9ae849cbd591577991922b8995ef34704618b23f1961770c9f31ebe346ca6089da391c96c6a11d,2c292189440176ae193a5326e82b67fe058603a5f12ab3382e69e2eaaf457e4f", + "7eff84aeca24260baa06b61394bdec8b760a0c6558dd1748d91d6f492e0779b7,1c182efc13f2468d880372f4809d5a5e7011dfbf,13d1c9c1d3ac10cc78c43a2f0724a6a2e06adf5844a4ab45ff4779af1f15029d,8ce4f2abb9775f7e3cea0fa75238ab75cf6908e3,d3e2938a69fdce888260003f6f1702e9d3392ab0,4569f2282b016fee5b583390e709dd285eb09b7510bbe092f37e5fef581a78b42729eb9f46088d1d52a00f2f57d1ffd48ab64b5c0dfc38d01bf2c793c977fcfc,a1804b2d4eabf9a4ac77531f5f12d1b12fa5d7042d7e526c6c59ea7d4259d338", + "c7acfcf801519b59c4750b06d6d55b1915f3a0317859685dd2ae337a6065d4bb,384c59c208e92c46e4fb8bcea9e286181ee4f956,4853fbb9eafeb0bfe2d717ad34973ea979413874e97d92d7a85c16a8fb61626e,e45f80b6cd0533e8b6f9a974b17c20244812e0fe,d531970c5f1ca7d0772513b32e8b75fa837c27fd,fc7946c37e09c86ce48e704f162e96c06cd227df7813dcc910fb56793a8cd5b0f205207292f6c7d34aeddeae80d3a6243409f2d4bd11e0f4eba5e6711df77586,cf385747877b360b3582331aa1473039946c57c59d7969988b103c26cd43c949", + "b53e7fb86d09133c5d1bfccae6a16652d26376784ec97995c9173f8d4d9151bc,69a8d04118b7f4e5c49a877ea2a1e6d9bdcc6dc5,33cb2e45fe278f822c9f8f0b0f6ca7c0aa84e588237a70e0870607756bdb18e0,f17ef3913819472407b45b9bf2bf454b4185bfe7,75cd9d71a818ccfc234c80cd89b6b52b898530bc,008892ec410fcc7197049a9967738edff5abeef1e29eb03a2b3f1939433f16ce284a9d3be887b3b1500161a38a617e8e467b4564bb6d030f617fc996d3a26dd2,b8b865556a937c3c0dbed23abe2d40ed424b5fb53d22ed83db9eec00dc15e4cf", + "7125adb44be6dc3bea98c348fc546b92371e99b4294d753c3a2c408447057a48,06fed168e3f0a8928d56c847364caeaf63c11f34,721e34ca27da076c1e18b51ffbf1f2921a431f55e83f85c4cbe679d5e081c120,023445e83064df92dcd60478cd68ea45f032d5c0,d0e99a8e4a7ba80bcc861b6dc81c29547dfd7dae,a485d3f5f22d70dae68176b76df8f8173adae876dcae8e93c5156277204a507484a50cc25b40e967ed75c4eaf29cda8e97ab8b05f72fa30a28e11ed9a30c6f7a,4e788e256ab33c5143425544bfa179e4a0a529142670dd45cda42f26a3b8d4f0", + "34ab9bc63b31a019e59af803cd9365500ed01e36e5d8e166d7fa22a3dd06a4b2,495804100e19df440a1026e016c3a55800064bed,203f617d00fada67c5d5f48736793d79d3b75633e8977d531a035b51df696853,4278ed1405c4d61d35bf2dbd8b0ad17cf8eb2de8,23656338b7894db5ca7c5804e91a128cf0d17acf,4ab854a2ce4f7a2ac71fb0b84b88f960cc0fd7467b9a6e298243b0117e8d38525876608fa403d43bceb2aee43abebac670db6e74a2f346cb1a254aa942cc1fbd,666855a84f4be9a469296f20dd660126490ecf2d7bacda3f9e2a0dd11ca20636", + "93dc29da56fac0a611c8c5014bc61a6c3861ae9def571818664c7e44b25a954d,ceb1b9394c434c5a1648112477c5f674ed4430ca,f3a1d0c012317a4802aa52ae17c03e6bb8f769d35c909af8c0dbab16fe238d79,31c690c105e778b5941492cdffa5a817adc14202,ac6975f571f6e961c3db6ac29cfc7e975b2aaa09,f2f758a0e28f40d2b13a590d57875295668f12725a1536b513b19f59b65f88f885229ef424f8b226ee5b53749097ca70aa8b6dbb3650779074775239c652b70c,f091844b69ab5e3075255831b61ef62712adecbb9403c4b2b4f2719786bc4405", + "f6372c5a3c6957b655d56167a4e723fc0eefdd3abf1857b2c7d797a0be0e4b0e,960b962cea70b57c7edc4f137261f94829957a3b,70eeaa3dc29f434da194e23bb5eb1001e9012bab15bec0fb9532c63f022c19a8,80f5a9119a99ef6bc04a1944f256fc8176216ad2,d535e38f334aa06538ea644849b80972a7fe6c6f,ac08b0031b5026157997b5c4a5f60df1c8afd39c5d7691033c72d65e4fa06312b48dd0cf46dd350188563c957ddabdb4b06ed2e9b4be2babcf640825358b555e,bf166ee74cf3c2dfcc88dd9c6d548438b9b76fa03df6589990997f44fa4b6f13" ) private lazy val hashes = lines.map { line => @@ -32,7 +32,8 @@ class HashingTest extends BitcoinSCryptoTest { val ripeMd160 = RipeMd160Digest.fromHex(arr(3)) val sha256Hash160 = Sha256Hash160Digest.fromHex(arr(4)) val hmac = ByteVector.fromValidHex(arr(5)) - (data, sha1, sha256, ripeMd160, sha256Hash160, hmac) + val sha3_256 = Sha3_256Digest.fromHex(arr(6)) + (data, sha1, sha256, ripeMd160, sha256Hash160, hmac, sha3_256) } it must "compute sha1" in { @@ -68,6 +69,12 @@ class HashingTest extends BitcoinSCryptoTest { assert(actual == expected) } + it must "compute sha3-256" in { + val expected = hashes.map(_._7) + val actual = hashes.map(_._1).map(BCryptoCryptoRuntime.sha3_256) + assert(actual == expected) + } + // From https://github.com/dgarage/NDLC/blob/d816c0c517611b336f09ceaa43d400ecb5ab909b/NDLC.Tests/Data/normalization_tests.json it must "normalize and serialize strings correctly" in { val singletons = Vector("\u00c5", "\u212b", "\u0041\u030a") 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 6743dabcf1..c0fb1c6b0e 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/CryptoUtilTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/CryptoUtilTest.scala @@ -238,4 +238,12 @@ class CryptoUtilTest extends BitcoinSCryptoTest { assert(CryptoUtil.checkEntropy(bytes)) } } + + it must "perform a SHA3-256 hash" in { + val hash = CryptoUtil.sha3_256(hex"") + val expected = + "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" + hash.hex must be(expected) + hash.flip.flip.hex must be(expected) + } } 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 e8682d9a1b..7e3acd6d4c 100644 --- a/crypto/.js/src/main/scala/org/bitcoins/crypto/BCryptoCryptoRuntime.scala +++ b/crypto/.js/src/main/scala/org/bitcoins/crypto/BCryptoCryptoRuntime.scala @@ -20,6 +20,7 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { private lazy val sha256 = SHA256Factory.create() private lazy val sha512 = SHA512Factory.create() private lazy val hmac = SHA512.hmac.apply().asInstanceOf[HMAC] + private lazy val sha3_256 = new SHA3_256 private lazy val randomBytesFunc: Int => ByteVector = { int => try { @@ -77,6 +78,15 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { Sha256Digest.fromBytes(hashByteVec) } + override def sha3_256(bytes: ByteVector): Sha3_256Digest = { + val buffer = CryptoJsUtil.toNodeBuffer(bytes) + sha3_256.init() + sha3_256.update(buffer) + val hashBuffer = sha3_256.`final`() + val hashByteVec = CryptoJsUtil.toByteVector(hashBuffer) + Sha3_256Digest.fromBytes(hashByteVec) + } + def sha512(bytes: ByteVector): ByteVector = { val buffer = CryptoJsUtil.toNodeBuffer(bytes) sha512.init() diff --git a/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/SHA3_256.scala b/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/SHA3_256.scala new file mode 100644 index 0000000000..bd0855edec --- /dev/null +++ b/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/SHA3_256.scala @@ -0,0 +1,17 @@ +package org.bitcoins.crypto.facade + +import org.bitcoins.crypto.Hasher + +import scala.scalajs.js +import scala.scalajs.js.annotation._ + +@js.native +@JSImport("bcrypto/lib/sha3-256.js", JSImport.Default) +class SHA3_256 extends Hasher { + + override def init(): Unit = js.native + + override def update(bytes: Buffer): Unit = js.native + + override def `final`(): Buffer = js.native +} 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 074cdde4b8..e1089d2279 100644 --- a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncycastleCryptoRuntime.scala +++ b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncycastleCryptoRuntime.scala @@ -114,6 +114,11 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { Sha256Digest(ByteVector(hash)) } + override def sha3_256(bytes: ByteVector): Sha3_256Digest = { + val hash = MessageDigest.getInstance("SHA3-256").digest(bytes.toArray) + Sha3_256Digest(ByteVector(hash)) + } + override def sha1(bytes: ByteVector): Sha1Digest = { val hash = MessageDigest.getInstance("SHA-1").digest(bytes.toArray).toList Sha1Digest(ByteVector(hash)) 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 d22131f676..903cb2a764 100644 --- a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/LibSecp256k1CryptoRuntime.scala +++ b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/LibSecp256k1CryptoRuntime.scala @@ -30,6 +30,10 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { BouncycastleCryptoRuntime.sha256(bytes) } + override def sha3_256(bytes: ByteVector): Sha3_256Digest = { + BouncycastleCryptoRuntime.sha3_256(bytes) + } + override def sha1(bytes: ByteVector): Sha1Digest = { BouncycastleCryptoRuntime.sha1(bytes) } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/CryptoRuntime.scala b/crypto/src/main/scala/org/bitcoins/crypto/CryptoRuntime.scala index b8c21cf430..1dff8607b6 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/CryptoRuntime.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/CryptoRuntime.scala @@ -34,6 +34,8 @@ trait CryptoRuntime { sha256(bitVector.toByteVector) } + def sha3_256(bytes: ByteVector): Sha3_256Digest + def taggedSha256(bytes: ByteVector, tag: String): Sha256Digest = { val tagHash = sha256(tag) val tagBytes = tagHash.bytes ++ tagHash.bytes diff --git a/crypto/src/main/scala/org/bitcoins/crypto/CryptoUtil.scala b/crypto/src/main/scala/org/bitcoins/crypto/CryptoUtil.scala index d2f0b1fcd1..aa62c8bd50 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/CryptoUtil.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/CryptoUtil.scala @@ -50,6 +50,11 @@ trait CryptoUtil extends CryptoRuntime { cryptoRuntime.taggedSha256(serializeForHash(str), tag) } + /** Performs SHA3-256(bytes) */ + override def sha3_256(bytes: ByteVector): Sha3_256Digest = { + cryptoRuntime.sha3_256(bytes) + } + /** Performs SHA1(bytes). */ override def sha1(bytes: ByteVector): Sha1Digest = { cryptoRuntime.sha1(bytes) diff --git a/crypto/src/main/scala/org/bitcoins/crypto/HashDigest.scala b/crypto/src/main/scala/org/bitcoins/crypto/HashDigest.scala index 8b77fa3dd6..9ca3edb016 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/HashDigest.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/HashDigest.scala @@ -246,3 +246,56 @@ object Sha256Hash160DigestBE extends Factory[Sha256Hash160DigestBE] { Sha256Hash160DigestBEImpl(bytes) } } + +/** Represents the result of SHA3-256() + */ +sealed trait Sha3_256Digest extends Any with HashDigest { + override def flip: Sha3_256DigestBE = Sha3_256DigestBE(bytes.reverse) +} + +object Sha3_256Digest extends Factory[Sha3_256Digest] { + + private case class Sha3_256DigestImpl(bytes: ByteVector) + extends AnyVal + with Sha3_256Digest { + override def toString = s"Sha3-256DigestImpl($hex)" + // $COVERAGE-ON$ + } + + override def fromBytes(bytes: ByteVector): Sha3_256Digest = { + require(bytes.length == 32, + // $COVERAGE-OFF$ + "Sha3-256Digest must be 32 bytes in size, got: " + bytes.length) + Sha3_256DigestImpl(bytes) + } + + private val e = ByteVector(Array.fill(32)(0.toByte)) + + val empty: Sha3_256Digest = Sha3_256Digest.fromBytes(e) + +} + +/** Represents the result of SHA3-256() + */ +sealed trait Sha3_256DigestBE extends Any with HashDigest { + override def flip: Sha3_256Digest = Sha3_256Digest(bytes.reverse) +} + +object Sha3_256DigestBE extends Factory[Sha3_256DigestBE] { + + private case class Sha3_256DigestBEImpl(bytes: ByteVector) + extends AnyVal + with Sha3_256DigestBE { + override def toString = s"Sha3-256DigestBEImpl($hex)" + // $COVERAGE-ON$ + } + + override def fromBytes(bytes: ByteVector): Sha3_256DigestBE = { + require(bytes.length == 32, + // $COVERAGE-OFF$ + "Sha3-256Digest must be 32 bytes in size, got: " + bytes.length) + Sha3_256DigestBEImpl(bytes) + } + + lazy val empty: Sha256DigestBE = Sha256DigestBE(ByteVector.low(32)) +} diff --git a/docs/node/node.md b/docs/node/node.md index 816d5a4239..9d4b1e9805 100644 --- a/docs/node/node.md +++ b/docs/node/node.md @@ -8,7 +8,7 @@ Bitcoin-s has node module that allows you to connect to the p2p network. ### Neutrino Node Bitcoin-s has experimental support for neutrino which is a new lite client proposal on the bitcoin p2p network. You can -read more about how neutrino works [here](https://suredbits.com/neutrino-what-is-it-and-why-we-need-it/). At this time, +read more about how neutrino works [here](https://suredbits.com/neutrino-what-is-it-and-why-we-need-it/). At this time, bitcoin-s only supports connecting to one trusted peer. #### Limitations @@ -113,7 +113,7 @@ val nodeF = for { peer <- peerF } yield { val dataMessageHandler = DataMessageHandler(chainApi) - NeutrinoNode(nodePeer = Vector(peer), + NeutrinoNode(configPeersOverride = Vector(peer), dataMessageHandler = dataMessageHandler, nodeConfig = nodeConfig, chainConfig = chainConfig, @@ -157,4 +157,4 @@ val cleanupF = for { } yield () Await.result(cleanupF, 60.seconds) -``` +``` \ No newline at end of file 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 6fb8f60877..c7013675b8 100644 --- a/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeTest.scala @@ -1,7 +1,9 @@ package org.bitcoins.node import akka.actor.Cancellable +import org.bitcoins.core.util.NetworkUtil import org.bitcoins.crypto.DoubleSha256DigestBE +import org.bitcoins.node.models.PeerDAO import org.bitcoins.server.BitcoinSAppConfig import org.bitcoins.testkit.BitcoinSTestAppConfig import org.bitcoins.testkit.node.fixture.NeutrinoNodeConnectedWithBitcoinds @@ -39,12 +41,13 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoinds => //checking all peers are connected val node = nodeConnectedWithBitcoind.node - val connFs = node.peers.indices.map(node.isConnected) + val connFs = node.peerManager.peers.indices.map(node.isConnected) val connF = Future.sequence(connFs).map(_.forall(_ == true)) val connAssertion = connF.map(assert(_)) //checking all peers are initialized - val isInitializedFs = node.peers.indices.map(node.isInitialized) + val isInitializedFs = + node.peerManager.peers.indices.map(node.isInitialized) val isInitializedF = for { _ <- connAssertion f <- Future.sequence(isInitializedFs).map(_.forall(_ == true)) @@ -60,6 +63,45 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { disconnF.map(assert(_)) } + it must "store peer after successful initialization" in { + nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoinds => + val node = nodeConnectedWithBitcoind.node + + val assertConnAndInit = for { + _ <- node.isConnected(0).map(assert(_)) + a2 <- node.isInitialized(0).map(assert(_)) + } yield a2 + + for { + _ <- assertConnAndInit + peerDbs <- PeerDAO()(executionContext, node.nodeAppConfig).findAll() + } yield { + val compares = for { + peer <- node.peerManager.peers + peerDb <- peerDbs + } yield { + val dbSocket = + NetworkUtil.parseInetSocketAddress(peerDb.address, peerDb.port) + + 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 + val localhost = Vector("localhost", "127.0.0.1") + localhost.contains(dbSocket.getHostString) && localhost.contains( + peer.socket.getHostString) + } + } + + hostMatch && dbSocket.getPort == peer.socket.getPort + } + + assert(compares.exists(p => p)) + } + } + it must "receive notification that a block occurred on the p2p network for neutrino" in { nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoinds => val node = nodeConnectedWithBitcoind.node @@ -137,7 +179,7 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { //checking all peers can be disconnected private def isAllDisconnectedF(node: Node): Future[Boolean] = { - val disconnFs = node.peers.indices.map(node.isDisconnected) + val disconnFs = node.peerManager.peers.indices.map(node.isDisconnected) val res = Future.sequence(disconnFs).map(_.forall(_ == true)) res } diff --git a/node-test/src/test/scala/org/bitcoins/node/networking/peer/PeerMessageReceiverTest.scala b/node-test/src/test/scala/org/bitcoins/node/networking/peer/PeerMessageReceiverTest.scala index d3e06e3fcd..b983b1769f 100644 --- a/node-test/src/test/scala/org/bitcoins/node/networking/peer/PeerMessageReceiverTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/networking/peer/PeerMessageReceiverTest.scala @@ -69,8 +69,9 @@ class PeerMessageReceiverTest extends NodeTestWithCachedBitcoindPair { verackMsgP = verackMsgP) val peerMsgReceiver = - PeerMessageReceiver(normal, node, node.peers.head)(system, - node.nodeAppConfig) + PeerMessageReceiver(normal, node, node.peerManager.peers.head)( + system, + node.nodeAppConfig) val newMsgReceiver = peerMsgReceiver.disconnect() @@ -108,8 +109,9 @@ class PeerMessageReceiverTest extends NodeTestWithCachedBitcoindPair { verackMsgP = verackMsgP) val peerMsgReceiver = - PeerMessageReceiver(normal, node, node.peers.head)(system, - node.nodeAppConfig) + PeerMessageReceiver(normal, node, node.peerManager.peers.head)( + system, + node.nodeAppConfig) val newMsgReceiver = peerMsgReceiver.initializeDisconnect() diff --git a/node/src/main/resources/hardcoded-peers.txt b/node/src/main/resources/hardcoded-peers.txt new file mode 100644 index 0000000000..6905ec635e --- /dev/null +++ b/node/src/main/resources/hardcoded-peers.txt @@ -0,0 +1,676 @@ +2.39.173.126:8333 +3.14.168.201:48333 +4.36.112.44:8333 +5.8.18.31:8333 +5.14.200.167:8333 +5.56.20.2:8333 +5.102.146.99:8333 +5.103.137.146:9333 +5.128.87.126:8333 +5.133.65.82:8333 +5.187.55.242:8333 +5.188.62.24:8333 +5.188.62.33:8333 +5.199.133.193:8333 +8.38.89.152:8333 +13.231.20.249:8333 +18.27.79.17:8333 +20.184.15.116:8433 +23.28.205.97:8333 +23.106.252.230:8333 +23.175.0.202:8333 +23.175.0.212:8333 +23.241.250.252:8333 +23.245.24.154:8333 +24.86.184.66:8333 +24.116.246.9:8333 +24.141.34.166:8333 +24.155.196.246:8333 +24.157.130.222:8333 +24.188.176.255:8333 +24.237.70.53:8333 +27.124.4.67:8333 +31.17.70.80:8333 +31.21.8.32:8333 +31.45.118.10:8333 +31.132.17.56:8333 +31.134.121.223:8333 +32.214.183.114:8333 +35.137.236.32:8333 +35.185.145.105:8333 +35.209.51.212:8333 +35.245.175.76:8333 +37.116.95.41:8333 +37.143.9.107:8333 +37.143.116.43:8333 +37.191.244.149:8333 +37.211.78.253:8333 +37.221.209.222:24333 +37.228.92.110:8333 +43.225.62.107:8333 +43.225.157.152:8333 +45.36.184.6:8333 +45.48.168.16:8333 +45.85.85.8:8333 +45.85.85.9:8333 +45.129.180.214:8333 +45.149.78.128:8333 +45.151.125.218:8333 +45.154.255.46:8333 +45.155.157.239:8333 +46.28.132.34:8333 +46.28.204.21:8333 +46.32.50.98:8333 +46.59.13.35:8333 +46.128.40.173:8333 +46.128.140.193:8333 +46.146.248.89:8333 +46.166.162.45:20001 +46.188.15.6:8333 +46.229.165.142:8333 +46.229.238.187:8333 +46.249.83.82:8333 +46.254.217.169:8333 +47.74.191.34:8333 +47.115.53.163:8333 +47.187.26.135:8333 +47.222.103.234:8333 +47.253.5.99:8333 +49.232.82.76:8333 +49.247.215.43:8333 +50.2.13.166:8333 +50.34.39.72:8333 +50.45.232.189:8333 +50.68.104.92:8333 +51.68.36.57:8333 +51.154.60.34:8333 +52.169.238.66:8333 +54.197.30.223:8333 +54.227.66.57:8333 +58.158.0.86:8333 +58.171.135.242:8333 +58.229.208.158:8333 +60.244.109.19:8333 +62.38.75.208:8333 +62.74.143.11:8333 +62.80.227.49:8333 +62.152.58.16:9421 +62.210.167.199:8333 +62.234.188.160:8333 +62.251.54.163:8333 +63.227.116.162:8333 +65.19.155.82:8333 +65.95.49.102:8333 +66.18.172.21:8333 +66.240.237.155:8333 +67.210.228.203:8333 +69.30.215.42:8333 +69.59.18.206:8333 +69.64.33.71:8333 +69.119.193.9:8333 +69.209.23.72:8333 +70.123.125.237:8333 +70.185.56.136:8333 +71.38.90.235:8333 +72.12.73.70:8333 +72.53.134.182:8333 +72.225.7.80:8333 +72.234.182.39:8333 +72.250.184.57:8333 +73.83.103.79:8333 +74.118.137.119:8333 +74.133.100.74:8333 +74.215.219.214:8333 +74.220.255.190:8333 +75.158.39.231:8333 +77.53.53.196:8333 +77.70.16.245:8333 +77.105.87.97:8333 +77.120.113.69:8433 +77.120.122.22:8433 +77.166.83.167:8333 +77.247.178.130:8333 +78.27.139.13:8333 +78.63.28.146:8333 +78.83.103.4:8333 +78.141.123.99:8333 +79.77.33.131:8333 +79.77.133.30:8333 +79.101.1.25:8333 +79.117.192.229:8333 +79.133.228.55:8333 +79.146.21.163:8333 +80.89.203.172:8001 +80.93.213.246:8333 +80.192.98.110:8334 +80.229.28.60:8333 +80.232.247.210:8333 +80.242.39.76:8333 +80.253.94.252:8333 +81.0.198.25:8333 +81.7.13.84:8333 +81.117.225.245:8333 +81.135.137.225:8333 +81.171.22.143:8333 +81.191.233.134:8333 +81.232.78.75:8333 +81.242.91.23:8333 +82.29.58.109:8333 +82.136.99.22:8333 +82.149.97.25:17567 +82.165.19.48:8333 +82.194.153.233:8333 +82.197.215.125:8333 +82.199.102.10:8333 +82.200.205.30:8333 +82.202.68.231:8333 +82.221.128.31:8333 +82.228.6.131:8333 +83.85.139.94:8333 +83.99.245.20:8333 +83.137.41.10:8333 +83.174.209.87:8333 +83.217.8.31:44420 +84.38.3.249:8333 +84.38.185.122:8333 +84.92.92.247:8333 +84.192.16.234:8333 +84.194.158.124:8333 +84.212.145.24:8333 +84.212.244.95:8333 +84.216.51.36:8333 +84.255.249.163:8333 +85.25.255.147:8333 +85.70.156.209:8333 +85.145.142.46:8333 +85.170.233.95:8333 +85.184.138.108:8333 +85.190.0.5:8333 +85.191.200.51:8333 +85.192.191.6:18500 +85.194.238.131:8333 +85.195.54.110:8333 +85.214.161.252:8333 +85.214.185.51:8333 +85.241.106.203:8333 +85.246.168.252:8333 +86.56.238.247:8333 +87.61.90.230:8333 +87.79.68.86:8333 +87.79.94.221:8333 +87.120.8.5:20008 +87.246.46.132:8333 +87.247.111.222:8333 +88.84.222.252:8333 +88.86.243.241:8333 +88.87.93.52:1691 +88.119.197.200:8333 +88.129.253.94:8333 +88.147.244.250:8333 +88.208.3.195:8333 +88.212.44.33:8333 +88.214.57.95:8333 +89.106.199.38:8333 +89.108.126.228:8333 +89.115.120.43:8333 +89.133.68.65:8333 +89.190.19.162:8333 +89.248.172.10:8333 +90.146.153.21:8333 +90.182.165.18:8333 +91.106.188.229:8333 +91.193.237.116:8333 +91.204.99.178:8333 +91.204.149.5:8333 +91.214.70.63:8333 +91.228.152.236:8333 +92.12.154.115:8333 +92.249.143.44:8333 +93.12.66.98:8333 +93.46.54.4:8333 +93.115.20.130:8333 +93.123.180.164:8333 +93.189.145.169:8333 +93.241.228.102:8333 +94.19.7.55:8333 +94.19.128.204:8333 +94.52.112.227:8333 +94.154.96.130:8333 +94.156.174.201:8333 +94.158.246.183:8333 +94.177.171.73:8333 +94.199.178.233:8100 +94.237.125.30:8333 +94.247.134.77:8333 +95.48.228.45:8333 +95.69.249.63:8333 +95.82.146.70:8333 +95.83.73.31:8333 +95.84.164.43:8333 +95.87.226.56:8333 +95.110.234.93:8333 +95.163.71.126:8333 +95.164.65.194:8333 +95.174.66.211:8333 +95.211.174.137:8333 +95.216.11.156:8433 +96.47.114.108:8333 +97.84.232.105:8333 +97.99.205.241:8333 +98.25.193.114:8333 +99.115.25.13:8333 +101.32.19.184:8333 +101.100.174.240:8333 +102.132.245.16:8333 +103.14.244.190:8333 +103.76.48.5:8333 +103.84.84.250:8335 +103.99.168.150:8333 +103.109.101.216:8333 +103.122.247.102:8333 +103.129.13.45:8333 +103.198.192.14:20008 +103.224.119.99:8333 +103.231.191.7:8333 +103.235.230.196:8333 +104.171.242.155:8333 +104.238.220.199:8333 +106.163.158.127:8333 +107.150.41.179:8333 +107.159.93.103:8333 +108.183.77.12:8333 +109.9.175.65:8333 +109.99.63.159:8333 +109.110.81.90:8333 +109.123.213.130:8333 +109.134.232.81:8333 +109.169.20.168:8333 +109.199.241.148:8333 +109.229.210.6:8333 +109.236.105.40:8333 +109.248.206.13:8333 +111.42.74.65:8333 +111.90.140.179:8333 +112.215.205.236:8333 +113.52.135.125:8333 +114.23.246.137:8333 +115.47.141.250:8885 +115.70.110.4:8333 +116.34.189.55:8333 +118.103.126.140:28333 +118.189.187.219:8333 +119.3.208.236:8333 +119.8.47.225:8333 +119.17.151.61:8333 +120.25.24.30:8333 +120.241.34.10:8333 +121.98.205.100:8333 +122.112.148.153:8339 +122.116.42.140:8333 +124.217.235.180:8333 +125.236.215.133:8333 +129.13.189.212:8333 +130.185.77.105:8333 +131.188.40.191:8333 +131.193.220.15:8333 +135.23.124.239:8333 +136.33.185.32:8333 +136.56.170.96:8333 +137.226.34.46:8333 +138.229.26.42:8333 +139.9.249.234:8333 +141.101.8.36:8333 +143.176.224.104:8333 +144.2.69.224:8333 +144.34.161.65:18333 +144.91.116.44:8333 +144.137.29.181:8333 +148.66.50.50:8335 +148.72.150.231:8333 +148.170.212.44:8333 +149.167.99.190:8333 +154.92.16.191:8333 +154.221.27.21:8333 +156.19.19.90:8333 +156.241.5.190:8333 +157.13.61.76:8333 +157.13.61.80:8333 +157.230.166.98:14391 +158.75.203.2:8333 +158.181.125.150:8333 +158.181.226.33:8333 +159.100.242.254:8333 +159.100.248.234:8333 +159.138.87.18:8333 +160.16.0.30:8333 +162.0.227.54:8333 +162.0.227.56:8333 +162.62.18.226:8333 +162.209.1.233:8333 +162.243.175.86:8333 +162.244.80.208:8333 +162.250.188.87:8333 +162.250.189.53:8333 +163.158.202.112:8333 +163.158.243.230:8333 +165.73.62.31:8333 +166.62.82.103:32771 +166.70.94.106:8333 +167.86.90.239:8333 +169.44.34.203:8333 +172.93.101.73:8333 +172.105.7.47:8333 +173.23.103.30:8000 +173.53.79.6:8333 +173.70.12.86:8333 +173.89.28.137:8333 +173.176.184.54:8333 +173.208.128.10:8333 +173.254.204.69:8333 +173.255.204.124:8333 +174.94.155.224:8333 +174.114.102.41:8333 +174.114.124.12:8333 +176.10.227.59:8333 +176.31.224.214:8333 +176.74.136.237:8333 +176.99.2.207:8333 +176.106.191.2:8333 +176.160.228.9:8333 +176.191.182.3:8333 +176.212.185.153:8333 +176.241.137.183:8333 +177.38.215.73:8333 +178.16.222.146:8333 +178.132.2.246:8333 +178.143.191.171:8333 +178.148.172.209:8333 +178.148.226.180:8333 +178.150.96.46:8333 +178.182.227.50:8333 +178.236.137.63:8333 +178.255.42.126:8333 +180.150.52.37:8333 +181.39.32.99:8333 +181.48.77.26:8333 +181.52.223.52:8333 +181.238.51.152:8333 +183.88.223.208:8333 +183.110.220.210:30301 +184.95.58.166:8336 +184.164.147.82:41333 +184.171.208.109:8333 +185.25.48.39:8333 +185.25.48.184:8333 +185.64.116.15:8333 +185.80.219.132:8333 +185.85.3.140:8333 +185.95.219.53:8333 +185.108.244.41:8333 +185.134.233.121:8333 +185.145.128.21:8333 +185.148.3.227:8333 +185.153.196.240:8333 +185.158.114.184:8333 +185.165.168.196:8333 +185.181.230.74:8333 +185.185.26.141:8111 +185.186.208.162:8333 +185.189.132.178:57780 +185.211.59.50:8333 +185.233.148.146:8333 +185.238.129.113:8333 +185.249.199.106:8333 +185.251.161.54:8333 +187.189.153.136:8333 +188.37.24.190:8333 +188.42.40.234:18333 +188.61.46.36:8333 +188.68.45.143:8333 +188.127.229.105:8333 +188.134.6.84:8333 +188.134.8.36:8333 +188.214.129.65:20012 +188.230.168.114:8333 +189.34.14.93:8333 +189.207.46.32:8333 +190.211.204.68:8333 +191.209.21.188:8333 +192.3.11.20:8333 +192.3.185.210:8333 +192.65.170.15:8333 +192.65.170.50:8333 +192.146.137.18:8333 +192.157.202.178:8333 +192.227.80.83:8333 +193.10.203.23:8334 +193.25.6.206:8333 +193.42.110.30:8333 +193.58.196.212:8333 +193.106.28.8:8333 +193.189.190.123:8333 +193.194.163.35:8333 +193.194.163.53:8333 +194.14.246.205:8333 +194.36.91.253:8333 +194.126.113.135:8333 +194.135.135.69:8333 +195.56.63.4:8333 +195.56.63.5:8333 +195.67.139.54:8333 +195.135.194.8:8333 +195.202.169.149:8333 +195.206.105.42:8333 +195.209.249.164:8333 +198.1.231.6:8333 +198.200.43.215:8333 +199.182.184.204:8333 +199.247.7.208:8333 +199.247.249.188:8333 +200.7.252.118:8333 +200.20.186.254:8333 +200.83.166.136:8333 +202.55.87.45:8333 +202.79.167.65:8333 +202.108.211.135:8333 +202.169.102.73:8333 +203.130.48.117:8885 +203.132.95.10:8333 +203.151.166.123:8333 +204.93.113.108:8333 +204.111.241.195:8333 +206.124.149.66:8333 +207.115.102.98:8333 +207.229.46.150:8333 +208.76.252.198:8333 +208.100.13.56:8333 +208.100.178.175:8333 +208.110.99.105:8333 +209.6.210.179:8333 +209.133.220.74:8333 +209.141.57.57:8333 +211.27.147.67:8333 +212.34.225.118:8333 +212.89.173.216:8333 +212.99.226.36:9020 +212.237.96.98:8333 +213.89.131.53:8333 +216.38.129.164:8333 +216.134.165.55:8333 +216.146.251.8:8333 +216.189.190.95:8333 +216.226.128.189:8333 +216.236.164.82:8333 +217.19.216.210:8333 +217.26.32.10:8333 +217.64.47.138:8333 +217.64.133.220:8333 +217.92.55.246:8333 +218.31.113.245:8333 +218.255.242.114:8333 +220.133.39.61:8333 +223.16.30.175:8333 +[2001:19f0:6001:306f:ec4:7aff:fe8f:66ec]:8333 +[2001:1bc0:cc::a001]:8333 +[2001:1c02:2f18:d00:b62e:99ff:fe49:d492]:8333 +[2001:4100:0:64::93]:8333 +[2001:4100:0:64:dcaf:afff:fe00:6707]:8333 +[2001:470:a:c13::2]:8333 +[2001:4801:7819:74:b745:b9d5:ff10:a61a]:8333 +[2001:4ba0:fffa:5d::93]:8333 +[2001:610:1908:ff01:f816:3eff:fe33:2e32]:8333 +[2001:638:a000:4140::ffff:191]:8333 +[2001:648:2800:131:4b1f:f6fc:20f7:f99f]:8333 +[2001:678:7dc:8::2]:8333 +[2001:678:cc8::1:10:88]:20008 +[2001:67c:1220:80c::93e5:dd2]:8333 +[2001:67c:1220:80c:e5dc:ad0c:9289:c28f]:8333 +[2001:67c:16dc:1201:5054:ff:fe17:4dac]:8333 +[2001:67c:2354:2::22]:8333 +[2001:67c:26b4:12:7ae3:b5ff:fe04:6f9c]:8333 +[2001:67c:2f0::20:fa]:8333 +[2001:718:801:311:5054:ff:fe19:c483]:8333 +[2001:8d8:87c:7c00::99:3c1]:8333 +[2001:8f1:1404:3700:8e49:715a:2e09:b634]:9444 +[2001:b07:5d29:99a5:194b:3874:d65e:a90d]:8333 +[2001:ba8:1f1:f0fe::2]:8333 +[2001:bc8:1200:0:dac4:97ff:fe2a:3554]:20008 +[2001:da8:100d:22:10fa:d85f:10f2:21fd]:8333 +[2001:da8:8001:7a39:f035:7d:b99f:eb79]:8333 +[2001:e42:103:100::30]:8333 +[2400:2412:103:c900:825:8f20:eaff:65c2]:8333 +[2400:4052:e20:4f00:69fe:bb33:7b1c:a1ca]:8333 +[2401:1800:7800:105:be76:4eff:fe1c:b35]:8333 +[2401:3900:2:1::2]:8333 +[2401:b140::44:150]:8333 +[2401:d002:4402:0:8f28:591a:6ea0:c683]:8333 +[2403:6200:8821:3d68:195b:87e9:6819:d5c8]:8333 +[2405:6580:2140:3a00:c28c:983:364b:5d70]:8333 +[2405:9800:b911:a18a:58eb:cd3c:9d82:ea4a]:8333 +[2405:aa00:2::40]:8333 +[2409:10:ca20:1df0:224:e8ff:fe1f:60d9]:8333 +[2409:8a1e:a9af:3660:1c5a:5b6b:8a2d:9848]:8333 +[2409:8a1e:a9af:3660:404:39ba:88f2:e8df]:8333 +[240b:10:9141:400:49b4:3a2e:1e5:84c]:8333 +[240d:1a:759:6000:a7b1:451a:8874:e1ac]:8333 +[240d:1a:759:6000:ddab:3141:4da0:8878]:8333 +[2600:8805:2400:14e:12dd:b1ff:fef2:3013]:8333 +[2601:602:8d80:b63:dc3e:24ff:fe92:5eb]:8333 +[2602:ffb6:4:2798:f816:3eff:fe2f:5441]:8333 +[2602:ffb6:4:739e:f816:3eff:fe00:c2b3]:8333 +[2602:ffb8::208:72:57:200]:8333 +[2604:1380:4111:9300::1]:8333 +[2604:4300:a:2e:21b:21ff:fe11:392]:8333 +[2604:4500::2e06]:8112 +[2604:5500:706a:4000:fc79:b9bb:1d7:c325]:8333 +[2604:5500:c134:4000::3fc]:32797 +[2604:6800:5e11:162:5c8f:d2ff:fe26:146f]:8333 +[2605:4d00::50]:8333 +[2605:6400:20:13bf:df1d:181c:83bb:22e8]:8333 +[2605:ae00:203::203]:8333 +[2605:c000:2a0a:1::102]:8333 +[2607:f2c0:f00e:300::54]:8333 +[2607:f2f8:ad40:bc1::1]:8333 +[2607:f470:8:1048:ae1f:6bff:fe70:7240]:8333 +[2607:ff28:800f:97:225:90ff:fe75:1110]:8333 +[2620:11c:5001:1118:d267:e5ff:fee9:e673]:8333 +[2620:6e:a000:2001::6]:8333 +[2804:14d:4c93:9809:9769:da80:1832:3480]:8333 +[2a00:1328:e101:c00::163]:8333 +[2a00:1398:4:2a03:215:5dff:fed6:1033]:8333 +[2a00:13a0:3015:1:85:14:79:26]:8333 +[2a00:1630:14::101]:8333 +[2a00:1768:2001:27::ef6a]:8333 +[2a00:1828:a004:2::666]:8333 +[2a00:1838:36:17::38cb]:8333 +[2a00:1838:36:7d::d3c6]:8333 +[2a00:1c10:2:709:58f7:e0ff:fe24:a0ba]:22220 +[2a00:1c10:2:709::217]:22220 +[2a00:1f40:5001:100::31]:8333 +[2a00:6020:1395:1400:baf7:2d43:60b3:198b]:8333 +[2a00:7c80:0:10b::3faf]:8333 +[2a00:8a60:e012:a00::21]:8333 +[2a00:ab00:603:84::3]:8333 +[2a00:bbe0:cc:0:62a4:4cff:fe23:7510]:8333 +[2a00:ca8:a1f:3025:f949:e442:c940:13e8]:8333 +[2a00:d2a0:a:3d00:1cdf:38bb:a7d6:c251]:8333 +[2a00:d880:11::20e]:8333 +[2a00:ec0:7207:9100:5f8f:25dd:2574:3982]:8333 +[2a00:f820:433::36]:8333 +[2a01:138:a017:b018::42]:8333 +[2a01:430:17:1::ffff:1153]:8333 +[2a01:490:16:301::2]:8333 +[2a01:4b00:807c:1b00:cda1:c6a:2bad:2418]:8333 +[2a01:4b00:80e7:5405::1]:8333 +[2a01:4f8:192:4212::2]:8433 +[2a01:7a0:2:137c::3]:8333 +[2a01:7a7:2:1467:ec4:7aff:fee2:5690]:8333 +[2a01:7c8:d002:10f:5054:ff:fe5c:dac7]:8333 +[2a01:7c8:d002:318:5054:ff:febe:cbb1]:8333 +[2a01:8740:1:ffc5::8c6a]:8333 +[2a01:cb00:f98:ca00:5054:ff:fed4:763d]:8333 +[2a01:cb14:cf6:bc00:21e5:f12e:32c8:145]:8333 +[2a01:d0:0:1c::245]:8333 +[2a01:d0:bef2::12]:8333 +[2a01:e35:2e40:6830:211:32ff:fea6:de3d]:8333 +[2a02:1205:c6aa:60c0:70d8:aaee:a82d:993c]:8333 +[2a02:169:502::614]:8333 +[2a02:180:1:1::5b8f:538c]:8333 +[2a02:348:62:5ef7::1]:8333 +[2a02:390:9000:0:218:7dff:fe10:be33]:8333 +[2a02:7aa0:1619::adc:8de0]:8333 +[2a02:7b40:b0df:8925::1]:8333 +[2a02:7b40:b905:37db::1]:8333 +[2a02:810d:8cbf:f3a8:96c6:91ff:fe17:ae1d]:8333 +[2a02:8389:1c0:9680:201:2eff:fe82:b3cc]:8333 +[2a02:a454:a516:1:517:928:7e0d:957c]:8333 +[2a02:af8:fab0:804:151:236:34:161]:8333 +[2a02:af8:fab0:808:85:234:145:132]:8333 +[2a02:e00:fff0:1e2::a]:8333 +[2a03:2260:3006:d:d307:5d1d:32ca:1fe8]:8333 +[2a03:6000:870:0:46:23:87:218]:8333 +[2a03:9da0:f6:1::2]:8333 +[2a03:c980:db:47::]:8333 +[2a03:e2c0:1ce::2]:8333 +[2a04:3544:1000:1510:706c:abff:fe6c:501c]:8333 +[2a04:52c0:101:383::2a87]:8333 +[2a04:52c0:101:3fb::4c27]:8333 +[2a04:ee41:83:50df:d908:f71d:2a86:b337]:8333 +[2a05:6d40:b94e:d100:225:90ff:fe0d:cfc2]:8333 +[2a05:e5c0:0:100:250:56ff:feb9:d6cb]:8333 +[2a05:fc87:1:6::2]:8333 +[2a05:fc87:4::8]:8333 +[2a07:5741:0:115d::1]:8333 +[2a07:a880:4601:1062:b4b4:bd2a:39d4:7acf]:51401 +[2a07:abc4::1:946]:8333 +[2a07:b400:1:34c::2:1002]:8333 +[2a0a:8c41::b4]:8333 +[2a0a:c801:1:7::183]:8333 +[2a0b:ae40:3:4a0a::15]:8333 +[2a0f:df00:0:254::46]:8333 +[2c0f:f598:5:1:1001::1]:8333 +[2c0f:fce8:0:400:b7c::1]:8333 +2g5qfdkn2vvcbqhzcyvyiitg4ceukybxklraxjnu7atlhd22gdwywaid.onion:8333 +2jmtxvyup3ijr7u6uvu7ijtnojx4g5wodvaedivbv74w4vzntxbrhvad.onion:8333 +37m62wn7dz3uqpathpc4qfmgrbupachj52nt3jbtbjugpbu54kbud7yd.onion:8333 +5g72ppm3krkorsfopcm2bi7wlv4ohhs4u4mlseymasn7g7zhdcyjpfid.onion:8333 +7cgwjuwi5ehvcay4tazy7ya6463bndjk6xzrttw5t3xbpq4p22q6fyid.onion:8333 +7pyrpvqdhmayxggpcyqn5l3m5vqkw3qubnmgwlpya2mdo6x7pih7r7id.onion:8333 +b64xcbleqmwgq2u46bh4hegnlrzzvxntyzbmucn3zt7cssm7y4ubv3id.onion:8333 +ejxefzf5fpst4mg2rib7grksvscl7p6fvjp6agzgfc2yglxnjtxc3aid.onion:8333 +fjdyxicpm4o42xmedlwl3uvk5gmqdfs5j37wir52327vncjzvtpfv7yd.onion:8333 +fpz6r5ppsakkwypjcglz6gcnwt7ytfhxskkfhzu62tnylcknh3eq6pad.onion:8333 +fzhn4uoxfbfss7h7d6ffbn266ca432ekbbzvqtsdd55ylgxn4jucm5qd.onion:8333 +gxo5anvfnffnftfy5frkgvplq3rpga2ie3tcblo2vl754fvnhgorn5yd.onion:8333 +ifdu5qvbofrt4ekui2iyb3kbcyzcsglazhx2hn4wfskkrx2v24qxriid.onion:8333 +itz3oxsihs62muvknc237xabl5f6w6rfznfhbpayrslv2j2ubels47yd.onion:8333 +lrjh6fywjqttmlifuemq3puhvmshxzzyhoqx7uoufali57eypuenzzid.onion:8333 +m7cbpjolo662uel7rpaid46as2otcj44vvwg3gccodnvaeuwbm3anbyd.onion:8333 +opnyfyeiibe5qo5a3wbxzbb4xdiagc32bbce46owmertdknta5mi7uyd.onion:8333 +owjsdxmzla6d7lrwkbmetywqym5cyswpihciesfl5qdv2vrmwsgy4uqd.onion:8333 +q7kgmd7n7h27ds4fg7wocgniuqb3oe2zxp4nfe4skd5da6wyipibqzqd.onion:8333 +rp7k2go3s5lyj3fnj6zn62ktarlrsft2ohlsxkyd7v3e3idqyptvread.onion:8333 +sys54sv4xv3hn3sdiv3oadmzqpgyhd4u4xphv4xqk64ckvaxzm57a7yd.onion:8333 +tddeij4qigtjr6jfnrmq6btnirmq5msgwcsdpcdjr7atftm7cxlqztid.onion:8333 +vi5bnbxkleeqi6hfccjochnn65lcxlfqs4uwgmhudph554zibiusqnad.onion:8333 +xqt25cobm5zqucac3634zfght72he6u3eagfyej5ellbhcdgos7t2had.onion:8333 diff --git a/node/src/main/scala/org/bitcoins/node/NeutrinoNode.scala b/node/src/main/scala/org/bitcoins/node/NeutrinoNode.scala index 967f67f7f5..d1c7a6ea07 100644 --- a/node/src/main/scala/org/bitcoins/node/NeutrinoNode.scala +++ b/node/src/main/scala/org/bitcoins/node/NeutrinoNode.scala @@ -22,11 +22,11 @@ import org.bitcoins.node.networking.peer.{ import scala.concurrent.Future case class NeutrinoNode( - nodePeer: Vector[Peer], private var dataMessageHandler: DataMessageHandler, nodeConfig: NodeAppConfig, chainConfig: ChainAppConfig, - actorSystem: ActorSystem) + actorSystem: ActorSystem, + configPeersOverride: Vector[Peer] = Vector.empty) extends Node { require( nodeConfig.nodeType == NodeType.NeutrinoNode, @@ -38,10 +38,10 @@ case class NeutrinoNode( override def chainAppConfig: ChainAppConfig = chainConfig - override val peers: Vector[Peer] = nodePeer - val controlMessageHandler: ControlMessageHandler = ControlMessageHandler(this) + override val peerManager: PeerManager = PeerManager(this, configPeersOverride) + override def getDataMessageHandler: DataMessageHandler = dataMessageHandler override def updateDataMessageHandler( @@ -55,7 +55,7 @@ case class NeutrinoNode( node <- super.start() chainApi <- chainApiFromDb() bestHash <- chainApi.getBestBlockHash() - _ <- randomPeerMsgSenderWithCompactFilters + _ <- peerManager.randomPeerMsgSenderWithCompactFilters .sendGetCompactFilterCheckPointMessage(stopHash = bestHash.flip) } yield { node.asInstanceOf[NeutrinoNode] @@ -84,7 +84,7 @@ case class NeutrinoNode( blockchains <- blockchainsF // Get all of our cached headers in case of a reorg cachedHeaders = blockchains.flatMap(_.headers).map(_.hashBE.flip) - _ <- randomPeerMsgSender.sendGetHeadersMessage(cachedHeaders) + _ <- peerManager.randomPeerMsgSender.sendGetHeadersMessage(cachedHeaders) _ <- syncFilters(bestFilterHeaderOpt = bestFilterHeaderOpt, bestFilterOpt = bestFilterOpt, bestBlockHeader = header, @@ -137,7 +137,7 @@ case class NeutrinoNode( chainApi: ChainApi, bestFilterOpt: Option[CompactFilterDb]): Future[Unit] = { val sendCompactFilterHeaderMsgF = { - randomPeerMsgSenderWithCompactFilters + peerManager.randomPeerMsgSenderWithCompactFilters .sendNextGetCompactFilterHeadersCommand( chainApi = chainApi, filterHeaderBatchSize = chainConfig.filterHeaderBatchSize, @@ -153,7 +153,7 @@ case class NeutrinoNode( //means we are not syncing filter headers, and our filters are NOT //in sync with our compact filter headers logger.info(s"Starting sync filters in NeutrinoNode.sync()") - randomPeerMsgSenderWithCompactFilters + peerManager.randomPeerMsgSenderWithCompactFilters .sendNextGetCompactFilterCommand( chainApi = chainApi, filterBatchSize = chainConfig.filterBatchSize, diff --git a/node/src/main/scala/org/bitcoins/node/Node.scala b/node/src/main/scala/org/bitcoins/node/Node.scala index 426f48b720..23f18714dd 100644 --- a/node/src/main/scala/org/bitcoins/node/Node.scala +++ b/node/src/main/scala/org/bitcoins/node/Node.scala @@ -10,28 +10,22 @@ import org.bitcoins.chain.models.{ CompactFilterHeaderDAO } import org.bitcoins.core.api.chain._ -import org.bitcoins.core.api.node.{NodeApi, NodeType} -import org.bitcoins.core.p2p.{NetworkPayload, ServiceIdentifier, TypeIdentifier} +import org.bitcoins.core.api.node.NodeApi +import org.bitcoins.core.p2p._ import org.bitcoins.core.protocol.transaction.Transaction import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE} import org.bitcoins.node.config.NodeAppConfig -import org.bitcoins.node.models.{ - BroadcastAbleTransaction, - BroadcastAbleTransactionDAO, - Peer -} +import org.bitcoins.node.models._ import org.bitcoins.node.networking.P2PClient import org.bitcoins.node.networking.peer.{ ControlMessageHandler, DataMessageHandler, - PeerMessageReceiver, PeerMessageSender } -import scala.collection.mutable import scala.concurrent.duration.DurationInt import scala.concurrent.{ExecutionContext, Future} -import scala.util.{Failure, Random, Success} +import scala.util.{Failure, Success} /** This a base trait for various kinds of nodes. It contains house keeping methods required for all nodes. */ @@ -45,39 +39,7 @@ trait Node extends NodeApi with ChainQueryApi with P2PLogger { implicit def executionContext: ExecutionContext = system.dispatcher - val peers: Vector[Peer] - - private val _peerServices: mutable.Map[Peer, ServiceIdentifier] = - mutable.Map.empty - - def peerServices: Map[Peer, ServiceIdentifier] = _peerServices.toMap - - def setPeerServices( - peer: Peer, - serviceIdentifier: ServiceIdentifier): Unit = { - _peerServices.put(peer, serviceIdentifier) - () - } - - def randomPeerMsgSenderWithService( - f: ServiceIdentifier => Boolean): PeerMessageSender = { - val filteredPeers = - peerServices.filter(p => f(p._2)).keys.toVector - if (filteredPeers.isEmpty) - throw new RuntimeException("No peers supporting compact filters!") - val peer = filteredPeers(Random.nextInt(filteredPeers.length)) - peerMsgSenders - .find(_.client.peer == peer) - .getOrElse(throw new RuntimeException("This should not happen.")) - } - - def randomPeerMsgSenderWithCompactFilters: PeerMessageSender = { - randomPeerMsgSenderWithService(_.nodeCompactFilters) - } - - def randomPeerMsgSender: PeerMessageSender = { - peerMsgSenders(Random.nextInt(peerMsgSenders.length)) - } + val peerManager: PeerManager /** The current data message handler. * It should be noted that the dataMessageHandler contains @@ -110,22 +72,9 @@ trait Node extends NodeApi with ChainQueryApi with P2PLogger { * object. Internally in [[org.bitcoins.node.networking.P2PClient p2p client]] you will see that * the [[ChainApi chain api]] is updated inside of the p2p client */ - lazy val clients: Vector[P2PClient] = { - val peerMsgRecvs: Vector[PeerMessageReceiver] = - peers.map(x => PeerMessageReceiver.newReceiver(node = this, peer = x)) - val zipped = peers.zip(peerMsgRecvs) - val p2p = zipped.map { case (peer, peerMsgRecv) => - P2PClient(context = system, - peer = peer, - peerMessageReceiver = peerMsgRecv, - onReconnect = sync) - } - p2p - } + def clients: Vector[P2PClient] = peerManager.clients - lazy val peerMsgSenders: Vector[PeerMessageSender] = { - clients.map(PeerMessageSender(_)) - } + def peerMsgSenders: Vector[PeerMessageSender] = peerManager.peerMsgSenders /** Sends the given P2P to our peer. * This method is useful for playing around @@ -150,6 +99,20 @@ trait Node extends NodeApi with ChainQueryApi with P2PLogger { def isDisconnected(idx: Int): Future[Boolean] = peerMsgSenders(idx).isDisconnected() + def initializePeer(peer: Peer): Future[Unit] = { + peerManager.peerDataOf(peer).peerMessageSender.connect() + val isInitializedF = AsyncUtil + .retryUntilSatisfiedF( + () => peerManager.peerDataOf(peer).peerMessageSender.isInitialized(), + maxTries = 50, + interval = 250.millis) + isInitializedF.failed + .foreach { err => + logger.error(s"Failed to initialize with peer=$peer with err=$err") + } + isInitializedF + } + /** Starts our node */ def start(): Future[Node] = { logger.info("Starting node") @@ -162,41 +125,14 @@ trait Node extends NodeApi with ChainQueryApi with P2PLogger { val chainApiF = startConfsF.flatMap(_ => chainApiFromDb()) - val startNodeF = { - val isInitializedFs = peerMsgSenders.indices.map { idx => - peerMsgSenders(idx).connect() - val isInitializedF = for { - _ <- AsyncUtil.retryUntilSatisfiedF(() => isInitialized(idx), - maxTries = 1024, - interval = 250.millis) - } yield () - isInitializedF.failed.foreach { err => - logger.error( - s"Failed to connect with peer=${peers(idx)} with err=$err") - } - isInitializedF.map { _ => - nodeAppConfig.nodeType match { - case NodeType.NeutrinoNode => { - if (peerServices(peers(idx)).nodeCompactFilters) { - logger.info(s"Our peer=${peers(idx)} has been initialized") - } else { - logger.info( - s"Our peer=${peers(idx)} does not support compact filters. Disconnecting.") - peerMsgSenders(idx).disconnect() - } - } - case NodeType.SpvNode => - case NodeType.BitcoindBackend => - case NodeType.FullNode => - } - } - } - - Future.sequence(isInitializedFs).map { _ => - logger.info(s"Our node has been full started. It took=${System - .currentTimeMillis() - start}ms") - this - } + val startNodeF = for { + peers <- peerManager.getPeers + _ = peers.foreach(peerManager.addPeer) + _ <- Future.sequence(peers.map(initializePeer)) + } yield { + logger.info(s"Our node has been full started. It took=${System + .currentTimeMillis() - start}ms") + this } val bestHashF = chainApiF.flatMap(_.getBestBlockHash()) @@ -272,7 +208,7 @@ trait Node extends NodeApi with ChainQueryApi with P2PLogger { // Get all of our cached headers in case of a reorg cachedHeaders = blockchains.flatMap(_.headers).map(_.hashBE.flip) - _ <- randomPeerMsgSender.sendGetHeadersMessage(cachedHeaders) + _ <- peerManager.randomPeerMsgSender.sendGetHeadersMessage(cachedHeaders) } yield { logger.info( s"Starting sync node, height=${header.height} hash=${header.hashBE}") @@ -306,8 +242,10 @@ trait Node extends NodeApi with ChainQueryApi with P2PLogger { logger.info(s"Sending out tx message for tx=$txIds") peerMsgSenders(0).sendInventoryMessage(transactions: _*) } else { - Future.failed(new RuntimeException( - s"Error broadcasting transaction $txIds, peer is disconnected ${peers(0)}")) + Future.failed( + new RuntimeException( + s"Error broadcasting transaction $txIds, peer is disconnected ${peerManager + .peers(0)}")) } } } yield res diff --git a/node/src/main/scala/org/bitcoins/node/PeerData.scala b/node/src/main/scala/org/bitcoins/node/PeerData.scala new file mode 100644 index 0000000000..f6a16a715d --- /dev/null +++ b/node/src/main/scala/org/bitcoins/node/PeerData.scala @@ -0,0 +1,44 @@ +package org.bitcoins.node + +import akka.actor.ActorSystem +import org.bitcoins.core.p2p.ServiceIdentifier +import org.bitcoins.node.config.NodeAppConfig +import org.bitcoins.node.models.Peer +import org.bitcoins.node.networking.P2PClient +import org.bitcoins.node.networking.peer.{ + PeerMessageReceiver, + PeerMessageSender +} + +/** PeerData contains objects specific to a peer associated together + */ +case class PeerData( + peer: Peer, + node: Node +)(implicit system: ActorSystem, nodeAppConfig: NodeAppConfig) { + + lazy val peerMessageSender: PeerMessageSender = PeerMessageSender(client) + + lazy val client: P2PClient = { + val peerMessageReceiver = + PeerMessageReceiver.newReceiver(node = node, peer = peer) + P2PClient( + context = system, + peer = peer, + peerMessageReceiver = peerMessageReceiver, + onReconnect = node.sync + ) + } + + private var _serviceIdentifier: Option[ServiceIdentifier] = None + + def serviceIdentifier: ServiceIdentifier = { + _serviceIdentifier.getOrElse( + throw new RuntimeException( + s"Tried using ServiceIdentifier for uninitialized peer $peer")) + } + + def setServiceIdentifier(serviceIdentifier: ServiceIdentifier): Unit = { + _serviceIdentifier = Some(serviceIdentifier) + } +} diff --git a/node/src/main/scala/org/bitcoins/node/PeerManager.scala b/node/src/main/scala/org/bitcoins/node/PeerManager.scala new file mode 100644 index 0000000000..9be628789f --- /dev/null +++ b/node/src/main/scala/org/bitcoins/node/PeerManager.scala @@ -0,0 +1,199 @@ +package org.bitcoins.node + +import akka.actor.ActorSystem +import org.bitcoins.core.p2p.{AddrV2Message, ServiceIdentifier} +import org.bitcoins.core.util.NetworkUtil +import org.bitcoins.node.config.NodeAppConfig +import org.bitcoins.node.models.{Peer, PeerDAO, PeerDb} +import org.bitcoins.node.networking.P2PClient +import org.bitcoins.node.networking.peer.PeerMessageSender +import scodec.bits.ByteVector + +import java.net.{InetAddress, UnknownHostException} +import scala.collection.mutable +import scala.concurrent.{ExecutionContext, Future} +import scala.io.Source +import scala.util.Random + +case class PeerManager(node: Node, configPeers: Vector[Peer] = Vector.empty)( + implicit + ec: ExecutionContext, + system: ActorSystem, + nodeAppConfig: NodeAppConfig) + extends P2PLogger { + + private val _peerData: mutable.Map[Peer, PeerData] = + mutable.Map.empty + + def peerData: Map[Peer, PeerData] = _peerData.toMap + + def peers: Vector[Peer] = peerData.keys.toVector + + def peerMsgSenders: Vector[PeerMessageSender] = + peerData.values + .map(_.peerMessageSender) + .toVector + + def clients: Vector[P2PClient] = peerData.values.map(_.client).toVector + + /** Returns peers by querying each dns seed once. These will be IPv4 addresses. */ + private def getPeersFromDnsSeeds: Vector[Peer] = { + val dnsSeeds = nodeAppConfig.network.dnsSeeds + val addresses = dnsSeeds + .flatMap(seed => { + try { + InetAddress + .getAllByName(seed) + } catch { + case _: UnknownHostException => + logger.debug(s"DNS seed $seed is unavailable") + Vector() + } + }) + .distinct + .filter(_.isReachable(500)) + .map(_.getHostAddress) + val inetSockets = addresses.map( + NetworkUtil.parseInetSocketAddress(_, nodeAppConfig.network.port)) + val peers = + inetSockets.map(Peer.fromSocket(_, nodeAppConfig.socks5ProxyParams)) + peers.toVector + } + + /** 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 + .getLines() + .toVector + .filter(nodeAppConfig.torConf.enabled || !_.contains(".onion")) + val inetSockets = addresses.map( + NetworkUtil.parseInetSocketAddress(_, nodeAppConfig.network.port)) + val peers = + inetSockets.map(Peer.fromSocket(_, nodeAppConfig.socks5ProxyParams)) + peers + } + + /** Returns all peers stored in database */ + private def getPeersFromDb: Future[Vector[Peer]] = { + val addressesF: Future[Vector[PeerDb]] = + PeerDAO().findAllWithTorFilter(nodeAppConfig.torConf.enabled) + val peersF = addressesF.map { addresses => + val inetSockets = addresses.map(a => { + NetworkUtil.parseInetSocketAddress(a.address, a.port) + }) + val peers = + inetSockets.map(Peer.fromSocket(_, nodeAppConfig.socks5ProxyParams)) + peers + } + peersF + } + + /** 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] = { + if (configPeers.nonEmpty) { + configPeers + } else { + val addresses = nodeAppConfig.peers.filter( + nodeAppConfig.torConf.enabled || !_.contains(".onion")) + val inetSockets = addresses.map( + NetworkUtil.parseInetSocketAddress(_, nodeAppConfig.network.port)) + val peers = + inetSockets.map(Peer.fromSocket(_, nodeAppConfig.socks5ProxyParams)) + peers + } + } + + /** Returns peers randomly taken from config, database, hardcoded peers, dns seeds in that order */ + def getPeers: Future[Vector[Peer]] = { + //currently this would only give the first peer from config + val peersFromConfig = getPeersFromConfig + val peersFromDbF = getPeersFromDb + val peersFromResources = getPeersFromResources + val maxConnectedPeers = nodeAppConfig.maxConnectedPeers + + val allF = for { + peersFromDb <- peersFromDbF + } yield { + val shuffledPeers = (Random.shuffle(peersFromConfig) ++ Random.shuffle( + peersFromDb) ++ Random.shuffle(peersFromResources)).distinct + + //getting peers from dns seeds takes a noticeable 5-8 sec so treating this separately + if (maxConnectedPeers > shuffledPeers.size) { + shuffledPeers.take(maxConnectedPeers) ++ getPeersFromDnsSeeds.take( + maxConnectedPeers - shuffledPeers.size) + } else { + shuffledPeers.take(maxConnectedPeers) + } + } + allF + } + + def addPeer(peer: Peer): Unit = { + if (!_peerData.contains(peer)) + _peerData.put(peer, PeerData(peer, node)) + else logger.debug(s"Peer $peer already added.") + () + } + + def removePeer(peer: Peer): Future[Unit] = { + if (_peerData.contains(peer)) { + val connF = peerData(peer).peerMessageSender.isConnected() + val disconnectF = connF.map { conn => + if (conn) peerData(peer).peerMessageSender.disconnect() + else Future.unit + } + for { + _ <- disconnectF + _ <- removePeer(peer) + } yield () + } else { + logger.debug(s"Key $peer not found in peerData") + Future.unit + } + } + + def randomPeerMsgSenderWithService( + f: ServiceIdentifier => Boolean): PeerMessageSender = { + val filteredPeers = + peerData.values.filter(p => f(p.serviceIdentifier)).toVector + if (filteredPeers.isEmpty) + throw new RuntimeException("No peers supporting compact filters!") + val randomPeerData = filteredPeers(Random.nextInt(filteredPeers.length)) + randomPeerData.peerMessageSender + } + + def randomPeerMsgSenderWithCompactFilters: PeerMessageSender = { + randomPeerMsgSenderWithService(_.nodeCompactFilters) + } + + def randomPeerMsgSender: PeerMessageSender = { + peerMsgSenders(Random.nextInt(peerMsgSenders.length)) + } + + def createInDb(peer: Peer): Future[PeerDb] = { + logger.debug(s"Adding peer to db $peer") + val addrBytes = + if (peer.socket.getHostString.contains(".onion")) + NetworkUtil.torV3AddressToBytes(peer.socket.getHostString) + else + InetAddress.getByName(peer.socket.getHostString).getAddress + val networkByte = addrBytes.length match { + case AddrV2Message.IPV4_ADDR_LENGTH => AddrV2Message.IPV4_NETWORK_BYTE + case AddrV2Message.IPV6_ADDR_LENGTH => AddrV2Message.IPV6_NETWORK_BYTE + case AddrV2Message.TOR_V3_ADDR_LENGTH => AddrV2Message.TOR_V3_NETWORK_BYTE + case unknownSize => + throw new IllegalArgumentException( + s"Unsupported address type of size $unknownSize bytes") + } + PeerDAO() + .upsertPeer(ByteVector(addrBytes), peer.socket.getPort, networkByte) + } + + //makes it more readable, compare peerManager.peerData(peer) vs peerManager.peerDataOf(peer) as peer is used thrice + //in a simple statement + /** get [[PeerData]] for a [[Peer]] */ + def peerDataOf(peer: Peer): PeerData = peerData(peer) +} diff --git a/node/src/main/scala/org/bitcoins/node/SpvNode.scala b/node/src/main/scala/org/bitcoins/node/SpvNode.scala index 571e14b807..6f79a4adef 100644 --- a/node/src/main/scala/org/bitcoins/node/SpvNode.scala +++ b/node/src/main/scala/org/bitcoins/node/SpvNode.scala @@ -19,11 +19,11 @@ import org.bitcoins.node.networking.peer.{ import scala.concurrent.Future case class SpvNode( - nodePeer: Vector[Peer], dataMessageHandler: DataMessageHandler, nodeConfig: NodeAppConfig, chainConfig: ChainAppConfig, - actorSystem: ActorSystem) + actorSystem: ActorSystem, + configPeersOverride: Vector[Peer] = Vector.empty) extends Node { require(nodeConfig.nodeType == NodeType.SpvNode, s"We need our SPV mode enabled to be able to construct a SPV node!") @@ -34,8 +34,6 @@ case class SpvNode( override def chainAppConfig: ChainAppConfig = chainConfig - override val peers: Vector[Peer] = nodePeer - private val _bloomFilter = new Mutable(BloomFilter.empty) def bloomFilter: BloomFilter = _bloomFilter.atomicGet @@ -44,6 +42,8 @@ case class SpvNode( override def getDataMessageHandler: DataMessageHandler = dataMessageHandler + override val peerManager: PeerManager = PeerManager(this, configPeersOverride) + def setBloomFilter(bloom: BloomFilter): SpvNode = { _bloomFilter.atomicSet(bloom) this @@ -92,7 +92,8 @@ case class SpvNode( _ <- AsyncUtil.retryUntilSatisfiedF(() => isConnected(0)) _ <- peerMsgSenders(0).sendFilterLoadMessage(bloomFilter) } yield { - logger.info(s"Sending bloomfilter=${bloomFilter.hex} to ${peers(0)}") + logger.info( + s"Sending bloomfilter=${bloomFilter.hex} to ${peerManager.peers(0)}") node.asInstanceOf[SpvNode] } } 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 1b7eb444c6..74fa408101 100644 --- a/node/src/main/scala/org/bitcoins/node/config/NodeAppConfig.scala +++ b/node/src/main/scala/org/bitcoins/node/config/NodeAppConfig.scala @@ -127,8 +127,14 @@ case class NodeAppConfig( } } + lazy val maxConnectedPeers: Int = { + if (config.hasPath("bitcoin-s.node.maxConnectedPeers")) + config.getInt("bitcoin-s.node.maxConnectedPeers") + else 1 + } + /** Creates either a neutrino node or a spv node based on the [[NodeAppConfig]] given */ - def createNode(peers: Vector[Peer])( + def createNode(peers: Vector[Peer] = Vector.empty[Peer])( chainConf: ChainAppConfig, system: ActorSystem): Future[Node] = { NodeAppConfig.createNode(peers)(this, chainConf, system) @@ -163,9 +169,19 @@ object NodeAppConfig extends AppConfigFactoryActorSystem[NodeAppConfig] { nodeConf.nodeType match { case NodeType.SpvNode => - dmhF.map(dmh => SpvNode(peers, dmh, nodeConf, chainConf, system)) + dmhF.map(dmh => + SpvNode(dmh, + nodeConf, + chainConf, + system, + configPeersOverride = peers)) case NodeType.NeutrinoNode => - dmhF.map(dmh => NeutrinoNode(peers, dmh, nodeConf, chainConf, system)) + dmhF.map(dmh => + NeutrinoNode(dmh, + nodeConf, + chainConf, + system, + configPeersOverride = peers)) case NodeType.FullNode => Future.failed(new RuntimeException("Not implemented")) case NodeType.BitcoindBackend => 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 62a1f01729..b7c736581c 100644 --- a/node/src/main/scala/org/bitcoins/node/models/PeerDAO.scala +++ b/node/src/main/scala/org/bitcoins/node/models/PeerDAO.scala @@ -1,5 +1,6 @@ package org.bitcoins.node.models +import org.bitcoins.core.p2p.AddrV2Message import org.bitcoins.db.{CRUD, SlickUtil} import org.bitcoins.node.config.NodeAppConfig import scodec.bits.ByteVector @@ -45,6 +46,13 @@ case class PeerDAO()(implicit ec: ExecutionContext, appConfig: NodeAppConfig) safeDatabase.run(q.delete) } + /** 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) + safeDatabase.run(q.result).map(_.toVector) + } + def upsertPeer( address: ByteVector, port: Int, 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 e8bf66137e..314bb582b5 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 @@ -1,5 +1,10 @@ package org.bitcoins.node.networking.peer +import org.bitcoins.core.api.node.{ + ExternalImplementationNodeType, + InternalImplementationNodeType, + NodeType +} import org.bitcoins.core.p2p._ import org.bitcoins.node.models.Peer import org.bitcoins.node.networking.peer.PeerMessageReceiverState._ @@ -31,13 +36,16 @@ case class ControlMessageHandler(node: Node)(implicit ec: ExecutionContext) case good: Initializing => val newState = good.withVersionMsg(versionMsg) - sender.sendVerackMessage() - node.setPeerServices(peer, versionMsg.services) + node.peerManager + .peerData(peer) + .setServiceIdentifier(versionMsg.services) val newRecv = peerMessageReceiver.toState(newState) - Future.successful(newRecv) - + for { + _ <- sender.sendVerackMessage() + _ <- onPeerInitialization(peer) + } yield newRecv } case VerAckMessage => @@ -75,4 +83,23 @@ case class ControlMessageHandler(node: Node)(implicit ec: ExecutionContext) Future.successful(peerMessageReceiver) } } + + def onPeerInitialization(peer: Peer): Future[Unit] = { + node.nodeAppConfig.nodeType match { + case nodeType: InternalImplementationNodeType => + nodeType match { + case NodeType.FullNode => + throw new Exception("Node cannot be FullNode") + case NodeType.NeutrinoNode => + node.peerManager.createInDb(peer).map(_ => ()) + case NodeType.SpvNode => + node.peerManager.createInDb(peer).map(_ => ()) + } + case nodeType: ExternalImplementationNodeType => + nodeType match { + case NodeType.BitcoindBackend => + throw new Exception("Node cannot be BitcoindBackend") + } + } + } } 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 a3ca005efc..897eceab6d 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 @@ -50,8 +50,9 @@ case class DataMessageHandler( peerMsgSender: PeerMessageSender, node: Node): Future[DataMessageHandler] = { - lazy val peerWithCompactFilters = node.randomPeerMsgSenderWithCompactFilters - lazy val randomPeer = node.randomPeerMsgSender + lazy val peerWithCompactFilters = + node.peerManager.randomPeerMsgSenderWithCompactFilters + lazy val randomPeer = node.peerManager.randomPeerMsgSender val resultF = payload match { case checkpoint: CompactFilterCheckPointMessage => 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 4def301bf9..003521ba2b 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestWithCachedBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestWithCachedBitcoind.scala @@ -114,7 +114,6 @@ trait NodeTestWithCachedBitcoind extends BaseNodeTest with CachedTor { appConfig.chainConf, appConfig.nodeConf) startedNode <- node.start() - //is it enough to just sync with one bitcoind client for a test? syncedNode <- syncNeutrinoNode(startedNode, bitcoinds(0)) } yield NeutrinoNodeConnectedWithBitcoinds(syncedNode, bitcoinds) } 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 57f70f91ce..3514ea3818 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala @@ -222,7 +222,15 @@ object NodeUnitTest extends P2PLogger { val chainApiF = ChainHandlerCached .fromDatabase(blockHeaderDAO, filterHeaderDAO, filterDAO) - chainApiF.map(buildNode(peer, _)) + val nodeF = chainApiF.map(buildNode(peer, _)) + for { + node <- nodeF + _ <- node.nodeConfig.start() + peers <- node.peerManager.getPeers + } yield { + peers.foreach(node.peerManager.addPeer) + node + } } def buildNode(peer: Peer, chainApi: ChainApi)(implicit @@ -233,7 +241,11 @@ object NodeUnitTest extends P2PLogger { val dmh = DataMessageHandler(chainApi) - NeutrinoNode(Vector(peer), dmh, nodeConf, chainConf, system) + NeutrinoNode(dmh, + nodeConf, + chainConf, + system, + configPeersOverride = Vector(peer)) } def buildPeerMessageReceiver(chainApi: ChainApi, peer: Peer)(implicit @@ -272,6 +284,7 @@ object NodeUnitTest extends P2PLogger { def destroyNode(node: Node)(implicit ec: ExecutionContext): Future[Unit] = { for { _ <- node.stop() + _ <- node.nodeAppConfig.stop() _ <- node.chainAppConfig.stop() } yield { () @@ -486,11 +499,12 @@ object NodeUnitTest extends P2PLogger { for { _ <- checkConfigF + _ <- nodeAppConfig.start() chainHandler <- ChainUnitTest.createChainHandler() } yield { val dmh = DataMessageHandler(chainHandler) SpvNode( - nodePeer = Vector(peer), + configPeersOverride = Vector(peer), dataMessageHandler = dmh, nodeConfig = nodeAppConfig, chainConfig = chainAppConfig, @@ -516,11 +530,12 @@ object NodeUnitTest extends P2PLogger { chainHandler <- ChainUnitTest.createChainHandler() } yield chainHandler val nodeF = for { + _ <- nodeAppConfig.start() peer <- createPeer(bitcoind) chainApi <- chainApiF } yield { val dmh = DataMessageHandler(chainApi) - NeutrinoNode(nodePeer = Vector(peer), + NeutrinoNode(configPeersOverride = Vector(peer), dataMessageHandler = dmh, nodeConfig = nodeAppConfig, chainConfig = chainAppConfig, @@ -548,11 +563,12 @@ object NodeUnitTest extends P2PLogger { } yield chainHandler val peersF = bitcoinds.map(createPeer(_)) val nodeF = for { + _ <- nodeAppConfig.start() chainApi <- chainApiF peers <- Future.sequence(peersF) } yield { val dmh = DataMessageHandler(chainApi) - NeutrinoNode(nodePeer = peers, + NeutrinoNode(configPeersOverride = peers, dataMessageHandler = dmh, nodeConfig = nodeAppConfig, chainConfig = chainAppConfig,