mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 10:46:42 +01:00
Storing peers in database (#3773)
* rebase * fix * fix * remove unwanted diffs * fix * formatting * changes from comments * Revert "changes from comments" This reverts commit eb8a795718dc590802a19c7ce4cce4501bd2de1f. * changes from comments * add PeerManager * add sha3-256 * add NetworkUtilTest * formatting
This commit is contained in:
parent
93c5121632
commit
a58ef1cd02
28 changed files with 1308 additions and 168 deletions
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
676
node/src/main/resources/hardcoded-peers.txt
Normal file
676
node/src/main/resources/hardcoded-peers.txt
Normal file
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
44
node/src/main/scala/org/bitcoins/node/PeerData.scala
Normal file
44
node/src/main/scala/org/bitcoins/node/PeerData.scala
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
199
node/src/main/scala/org/bitcoins/node/PeerManager.scala
Normal file
199
node/src/main/scala/org/bitcoins/node/PeerManager.scala
Normal file
|
@ -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)
|
||||
}
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 =>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 =>
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue