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:
Shreyansh 2022-01-09 18:51:59 +05:30 committed by GitHub
parent 93c5121632
commit a58ef1cd02
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1308 additions and 168 deletions

View file

@ -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,

View file

@ -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)
}
}

View file

@ -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"
)
}

View file

@ -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"
}

View file

@ -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")

View file

@ -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)
}
}

View file

@ -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()

View file

@ -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
}

View file

@ -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))

View file

@ -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)
}

View file

@ -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

View file

@ -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)

View file

@ -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))
}

View file

@ -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,

View file

@ -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
}

View file

@ -69,7 +69,8 @@ class PeerMessageReceiverTest extends NodeTestWithCachedBitcoindPair {
verackMsgP = verackMsgP)
val peerMsgReceiver =
PeerMessageReceiver(normal, node, node.peers.head)(system,
PeerMessageReceiver(normal, node, node.peerManager.peers.head)(
system,
node.nodeAppConfig)
val newMsgReceiver = peerMsgReceiver.disconnect()
@ -108,7 +109,8 @@ class PeerMessageReceiverTest extends NodeTestWithCachedBitcoindPair {
verackMsgP = verackMsgP)
val peerMsgReceiver =
PeerMessageReceiver(normal, node, node.peers.head)(system,
PeerMessageReceiver(normal, node, node.peerManager.peers.head)(
system,
node.nodeAppConfig)
val newMsgReceiver = peerMsgReceiver.initializeDisconnect()

View 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

View file

@ -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,

View file

@ -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,42 +125,15 @@ 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 { _ =>
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())
val bestHeightF = chainApiF.flatMap(_.getBestHashBlockHeight())
@ -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

View 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)
}
}

View 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)
}

View file

@ -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]
}
}

View file

@ -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 =>

View file

@ -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,

View file

@ -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")
}
}
}
}

View file

@ -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 =>

View file

@ -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)
}

View file

@ -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,