pickynode 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +3 -0
- data/.rubocop.yml +14 -3
- data/.ruby-version +1 -1
- data/.travis.yml +2 -2
- data/Gemfile +4 -2
- data/LICENSE +1 -1
- data/README.md +4 -3
- data/Rakefile +0 -0
- data/bin/pickynode +4 -2
- data/lib/pickynode.rb +57 -30
- data/pickynode.gemspec +5 -3
- data/spec/mocks.rb +85 -76
- data/spec/pickynode_spec.rb +64 -54
- metadata +42 -16
- data/Gemfile.lock +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e5fccd137dcf0d78b38edab501a8c3c02b5d1c1dc80ffafcf65cdc18d503906b
|
4
|
+
data.tar.gz: c0c8a24d017f7e23404a91dd75c0ef7fcc9daf7317a49429a272a0e093a75f5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5f709d9f1ae5802c2ae07b9c7445882add45955af0afe9bee0b00e89b51c8c33a9283cbf5b95f4c0cc2c7ae58015d6114c5b8e53403c0965de7dd6b3218a08b
|
7
|
+
data.tar.gz: fa2e7689fea07663d5eda913742fdd0278c4b030f6c9b59fea7d3677e4bbb29bd0d67ac2e8b98ba36590521a53fe2be901fde83a1b3bb1cd0628e91e301845bf
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,8 +1,19 @@
|
|
1
|
-
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.5
|
3
|
+
NewCops: disable
|
4
|
+
Metrics/ClassLength:
|
2
5
|
Enabled: false
|
3
6
|
Metrics/BlockLength:
|
4
7
|
ExcludedMethods: ['describe', 'context']
|
5
|
-
Style/IndentHeredoc:
|
6
|
-
Enabled: false
|
7
8
|
Style/NumericPredicate:
|
8
9
|
Enabled: false
|
10
|
+
Lint/RaiseException:
|
11
|
+
Enabled: true
|
12
|
+
Lint/StructNewOverride:
|
13
|
+
Enabled: true
|
14
|
+
Style/HashEachMethods:
|
15
|
+
Enabled: true
|
16
|
+
Style/HashTransformKeys:
|
17
|
+
Enabled: true
|
18
|
+
Style/HashTransformValues:
|
19
|
+
Enabled: true
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.3
|
1
|
+
2.5.3
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
source 'https://rubygems.org'
|
4
|
-
ruby '>= 2.0'
|
4
|
+
ruby '>= 2.5.0'
|
5
5
|
|
6
6
|
gem 'awesome_print', '~> 1.7'
|
7
|
+
gem 'base64', '~> 0.2'
|
8
|
+
gem 'optimist', '~> 3.0'
|
9
|
+
gem 'ostruct', '~> 0.6'
|
7
10
|
gem 'rake', '~> 12.0'
|
8
11
|
gem 'rspec', '~> 3.6'
|
9
12
|
gem 'rubocop', '~> 0.48'
|
10
13
|
gem 'simplecov', '~> 0.14', require: false, group: :test
|
11
|
-
gem 'trollop', '~> 2.1'
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[![Gem Version](https://badge.fury.io/rb/pickynode.svg)](https://badge.fury.io/rb/pickynode) [![Build Status](https://travis-ci.
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/pickynode.svg)](https://badge.fury.io/rb/pickynode) [![Build Status](https://app.travis-ci.com/zquestz/pickynode.svg?branch=master&status=passed)](https://app.travis-ci.com/github/zquestz/pickynode) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
|
2
2
|
# pickynode
|
3
3
|
|
4
4
|
Some people are picky about the bitcoin nodes they connect to.
|
@@ -45,7 +45,7 @@ pickynode --disconnect=USER_AGENT_FILTER
|
|
45
45
|
### Help:
|
46
46
|
|
47
47
|
```
|
48
|
-
pickynode v0.
|
48
|
+
pickynode v0.2.0
|
49
49
|
Options:
|
50
50
|
-a, --add=<s> Add node type
|
51
51
|
-c, --connect=<s> Connect to node type
|
@@ -55,8 +55,9 @@ Options:
|
|
55
55
|
-o, --output Output commands
|
56
56
|
-s, --disconnect=<s> Disconnect from node type
|
57
57
|
-l, --limit=<i> Limit number of nodes to add/connect
|
58
|
+
-t, --ticker=<s> Currency ticker symbol (BCH/BTC) (default: BCH)
|
58
59
|
-v, --version Print version and exit
|
59
60
|
-h, --help Show this message
|
60
61
|
```
|
61
62
|
|
62
|
-
The --add and --connect commands pull data from
|
63
|
+
The --add and --connect commands pull data from the Blockchair API.
|
data/Rakefile
CHANGED
File without changes
|
data/bin/pickynode
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
require 'pickynode'
|
5
5
|
|
6
|
-
opts =
|
6
|
+
opts = Optimist.options do
|
7
7
|
version "pickynode v#{Pickynode::VERSION}"
|
8
8
|
opt :add, 'Add node type', type: :string
|
9
9
|
opt :connect, 'Connect to node type', type: :string
|
@@ -13,7 +13,9 @@ opts = Trollop.options do
|
|
13
13
|
opt :output, 'Output commands'
|
14
14
|
opt :disconnect, 'Disconnect from node type', type: :string
|
15
15
|
opt :limit, 'Limit number of nodes to add/connect', type: :integer
|
16
|
+
opt :ticker, 'Currency ticker symbol (BCH/BTC)', type: :string, default: 'BCH'
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
+
Optimist.die :limit, 'must be positive' if opts[:limit] && opts[:limit] <= 0
|
20
|
+
Optimist.die :ticker, 'must be BCH or BTC' unless %w[BCH BTC].include?(opts[:ticker])
|
19
21
|
Pickynode.new(opts).run
|
data/lib/pickynode.rb
CHANGED
@@ -3,13 +3,13 @@
|
|
3
3
|
require 'awesome_print'
|
4
4
|
require 'json'
|
5
5
|
require 'net/http'
|
6
|
-
require '
|
6
|
+
require 'optimist'
|
7
7
|
require 'uri'
|
8
8
|
|
9
9
|
# Allows you to easily add/ban/connect/disconnect nodes
|
10
10
|
# based on User Agent.
|
11
11
|
class Pickynode
|
12
|
-
VERSION = '0.
|
12
|
+
VERSION = '0.2.0'
|
13
13
|
|
14
14
|
def initialize(opts = {})
|
15
15
|
@opts = opts
|
@@ -20,22 +20,24 @@ class Pickynode
|
|
20
20
|
|
21
21
|
validate_limit(limit)
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
blockchair_addr_types
|
24
|
+
.select { |_, v| v.include?(filter) }
|
25
|
+
.each_with_index do |(k, _), i|
|
26
|
+
break if limit == i
|
27
|
+
|
28
|
+
run_cmd(%(bitcoin-cli addnode "#{k}" "add"))
|
29
|
+
end
|
29
30
|
end
|
30
31
|
|
31
32
|
def ban(filter)
|
32
33
|
return unless filter
|
33
|
-
|
34
|
-
|
34
|
+
|
35
|
+
addr_types
|
36
|
+
.select { |_, v| v.include?(filter) }
|
37
|
+
.each do |k, _|
|
35
38
|
u = URI.parse("https://#{k}")
|
36
39
|
run_cmd(%(bitcoin-cli setban "#{u.host}" "add"))
|
37
40
|
end
|
38
|
-
end
|
39
41
|
end
|
40
42
|
|
41
43
|
def connect(filter, limit = nil)
|
@@ -43,19 +45,23 @@ class Pickynode
|
|
43
45
|
|
44
46
|
validate_limit(limit)
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
blockchair_addr_types
|
49
|
+
.select { |_, v| v.include?(filter) }
|
50
|
+
.each_with_index do |(k, _), i|
|
51
|
+
break if limit == i
|
52
|
+
|
53
|
+
run_cmd(%(bitcoin-cli addnode "#{k}" "onetry"))
|
54
|
+
end
|
52
55
|
end
|
53
56
|
|
54
57
|
def disconnect(filter)
|
55
58
|
return unless filter
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
+
|
60
|
+
addr_types
|
61
|
+
.select { |_, v| v.include?(filter) }
|
62
|
+
.each do |k, _|
|
63
|
+
run_cmd(%(bitcoin-cli disconnectnode "#{k}"))
|
64
|
+
end
|
59
65
|
end
|
60
66
|
|
61
67
|
def display
|
@@ -78,7 +84,7 @@ class Pickynode
|
|
78
84
|
|
79
85
|
def clear_cache
|
80
86
|
@addr_types = nil
|
81
|
-
@
|
87
|
+
@blockchair_addr_types = nil
|
82
88
|
end
|
83
89
|
|
84
90
|
private
|
@@ -95,6 +101,7 @@ class Pickynode
|
|
95
101
|
|
96
102
|
def addr_types
|
97
103
|
return @addr_types if @addr_types
|
104
|
+
|
98
105
|
nodes = getpeerinfo
|
99
106
|
parsed_nodes = JSON.parse(nodes)
|
100
107
|
@addr_types = parsed_nodes.map do |n|
|
@@ -104,22 +111,42 @@ class Pickynode
|
|
104
111
|
{}
|
105
112
|
end
|
106
113
|
|
107
|
-
def
|
108
|
-
return @
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
114
|
+
def blockchair_addr_types
|
115
|
+
return @blockchair_addr_types if @blockchair_addr_types
|
116
|
+
|
117
|
+
parsed_nodelist = JSON.parse(blockchair_snapshot)
|
118
|
+
@blockchair_addr_types = parsed_nodelist['data']['nodes'].transform_values do |v|
|
119
|
+
v['version']
|
120
|
+
end
|
113
121
|
rescue JSON::ParserError
|
114
122
|
{}
|
115
123
|
end
|
116
124
|
|
117
|
-
def
|
118
|
-
|
125
|
+
def blockchair_snapshot
|
126
|
+
chain = case @opts[:ticker]
|
127
|
+
when 'BCH'
|
128
|
+
'bitcoin-cash'
|
129
|
+
when 'BTC'
|
130
|
+
'bitcoin'
|
131
|
+
end
|
132
|
+
|
133
|
+
Net::HTTP.get(URI.parse("https://api.blockchair.com/#{chain}/nodes"))
|
119
134
|
end
|
120
135
|
|
121
136
|
def getinfo
|
122
|
-
|
137
|
+
getblockchaininfo.merge(getnetworkinfo)
|
138
|
+
rescue JSON::ParserError
|
139
|
+
{}
|
140
|
+
end
|
141
|
+
|
142
|
+
def getblockchaininfo
|
143
|
+
JSON.parse(`bitcoin-cli getblockchaininfo`)
|
144
|
+
rescue JSON::ParserError
|
145
|
+
{}
|
146
|
+
end
|
147
|
+
|
148
|
+
def getnetworkinfo
|
149
|
+
JSON.parse(`bitcoin-cli getnetworkinfo`)
|
123
150
|
rescue JSON::ParserError
|
124
151
|
{}
|
125
152
|
end
|
data/pickynode.gemspec
CHANGED
@@ -15,13 +15,15 @@ bitcoin nodes they connect to."
|
|
15
15
|
s.executables << 'pickynode'
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.require_paths = ['lib']
|
18
|
-
s.required_ruby_version = '>= 2.
|
18
|
+
s.required_ruby_version = '>= 2.5'
|
19
19
|
|
20
20
|
s.add_dependency 'awesome_print', '~> 1.7'
|
21
|
-
s.add_dependency '
|
21
|
+
s.add_dependency 'base64', '~> 0.2'
|
22
|
+
s.add_dependency 'optimist', '~> 3.0'
|
23
|
+
s.add_dependency 'ostruct', '~> 0.6'
|
22
24
|
|
23
|
-
s.add_development_dependency 'rspec', '~> 3.6'
|
24
25
|
s.add_development_dependency 'rake', '~> 12.0'
|
26
|
+
s.add_development_dependency 'rspec', '~> 3.6'
|
25
27
|
s.add_development_dependency 'rubocop', '~> 0.48'
|
26
28
|
s.add_development_dependency 'simplecov', '~> 0.14'
|
27
29
|
end
|
data/spec/mocks.rb
CHANGED
@@ -1,84 +1,93 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
{
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
BLOCKCHAIR_SNAPSHOT = <<~HEREDOC
|
4
|
+
{
|
5
|
+
"data": {
|
6
|
+
"nodes": {
|
7
|
+
"88.99.199.87:8333": {
|
8
|
+
"version": "\/BitcoinUnlimited:1.0.2(EB16; AD12)\/",
|
9
|
+
"country": "US",
|
10
|
+
"height": 555417,
|
11
|
+
"flags": 37
|
12
|
+
},
|
13
|
+
"[2a01:e34:ee3a:5730:21f:5bff:fec5:e356]:8333": {
|
14
|
+
"version": "\/Satoshi:0.14.0\/",
|
15
|
+
"country": "US",
|
16
|
+
"height": 555416,
|
17
|
+
"flags": 37
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
11
21
|
}
|
12
|
-
}
|
13
|
-
HEREDOC
|
14
|
-
|
15
|
-
NODE_INFO = <<-HEREDOC
|
16
|
-
{
|
17
|
-
"version": 1020500,
|
18
|
-
"protocolversion": 70012,
|
19
|
-
"blocks": 467548,
|
20
|
-
"timeoffset": 0,
|
21
|
-
"connections": 154,
|
22
|
-
"proxy": "",
|
23
|
-
"difficulty": 559970892890.8381,
|
24
|
-
"testnet": false,
|
25
|
-
"paytxfee": 0.00000000,
|
26
|
-
"relayfee": 0.00001000,
|
27
|
-
"errors": ""
|
28
|
-
}
|
29
22
|
HEREDOC
|
30
23
|
|
31
|
-
|
32
|
-
[
|
24
|
+
NODE_INFO = <<~HEREDOC
|
33
25
|
{
|
34
|
-
"
|
35
|
-
"
|
36
|
-
"
|
37
|
-
"
|
38
|
-
"
|
39
|
-
"
|
40
|
-
"
|
41
|
-
"
|
42
|
-
"
|
43
|
-
"
|
44
|
-
"
|
45
|
-
"pingtime": 0.369602,
|
46
|
-
"minping": 0.210565,
|
47
|
-
"version": 70002,
|
48
|
-
"subver": "/FirstClient/",
|
49
|
-
"inbound": true,
|
50
|
-
"startingheight": 435862,
|
51
|
-
"banscore": 0,
|
52
|
-
"synced_headers": 467515,
|
53
|
-
"synced_blocks": -1,
|
54
|
-
"inflight": [
|
55
|
-
],
|
56
|
-
"whitelisted": false
|
57
|
-
},
|
58
|
-
{
|
59
|
-
"id": 3,
|
60
|
-
"addr": "[2a01:e34:ee3a:5730:21f:5bff:fec5:e356]:8333",
|
61
|
-
"addrlocal": "[2a01:e34:ee3a:5730:21f:5bff:fec5:e356]:8333",
|
62
|
-
"services": "0000000000000005",
|
63
|
-
"relaytxes": true,
|
64
|
-
"lastsend": 1495412829,
|
65
|
-
"lastrecv": 1495412830,
|
66
|
-
"bytessent": 10235040,
|
67
|
-
"bytesrecv": 2729345,
|
68
|
-
"conntime": 1495393262,
|
69
|
-
"timeoffset": -11,
|
70
|
-
"pingtime": 0.275245,
|
71
|
-
"minping": 0.07081899999999999,
|
72
|
-
"version": 80002,
|
73
|
-
"subver": "/SecondClient/",
|
74
|
-
"inbound": false,
|
75
|
-
"startingheight": 467483,
|
76
|
-
"banscore": 0,
|
77
|
-
"synced_headers": 467515,
|
78
|
-
"synced_blocks": 467515,
|
79
|
-
"inflight": [
|
80
|
-
],
|
81
|
-
"whitelisted": false
|
26
|
+
"version": 1020500,
|
27
|
+
"protocolversion": 70012,
|
28
|
+
"blocks": 467548,
|
29
|
+
"timeoffset": 0,
|
30
|
+
"connections": 154,
|
31
|
+
"proxy": "",
|
32
|
+
"difficulty": 559970892890.8381,
|
33
|
+
"testnet": false,
|
34
|
+
"paytxfee": 0.00000000,
|
35
|
+
"relayfee": 0.00001000,
|
36
|
+
"errors": ""
|
82
37
|
}
|
83
|
-
|
38
|
+
HEREDOC
|
39
|
+
|
40
|
+
PEER_INFO = <<~HEREDOC
|
41
|
+
[
|
42
|
+
{
|
43
|
+
"id": 2,
|
44
|
+
"addr": "131.114.88.218:33422",
|
45
|
+
"addrlocal": "67.188.11.253:8333",
|
46
|
+
"services": "0000000000000000",
|
47
|
+
"relaytxes": true,
|
48
|
+
"lastsend": 1495412829,
|
49
|
+
"lastrecv": 1495412825,
|
50
|
+
"bytessent": 5200917,
|
51
|
+
"bytesrecv": 2044140,
|
52
|
+
"conntime": 1495393261,
|
53
|
+
"timeoffset": -24,
|
54
|
+
"pingtime": 0.369602,
|
55
|
+
"minping": 0.210565,
|
56
|
+
"version": 70002,
|
57
|
+
"subver": "/FirstClient/",
|
58
|
+
"inbound": true,
|
59
|
+
"startingheight": 435862,
|
60
|
+
"banscore": 0,
|
61
|
+
"synced_headers": 467515,
|
62
|
+
"synced_blocks": -1,
|
63
|
+
"inflight": [
|
64
|
+
],
|
65
|
+
"whitelisted": false
|
66
|
+
},
|
67
|
+
{
|
68
|
+
"id": 3,
|
69
|
+
"addr": "[2a01:e34:ee3a:5730:21f:5bff:fec5:e356]:8333",
|
70
|
+
"addrlocal": "[2a01:e34:ee3a:5730:21f:5bff:fec5:e356]:8333",
|
71
|
+
"services": "0000000000000005",
|
72
|
+
"relaytxes": true,
|
73
|
+
"lastsend": 1495412829,
|
74
|
+
"lastrecv": 1495412830,
|
75
|
+
"bytessent": 10235040,
|
76
|
+
"bytesrecv": 2729345,
|
77
|
+
"conntime": 1495393262,
|
78
|
+
"timeoffset": -11,
|
79
|
+
"pingtime": 0.275245,
|
80
|
+
"minping": 0.07081899999999999,
|
81
|
+
"version": 80002,
|
82
|
+
"subver": "/SecondClient/",
|
83
|
+
"inbound": false,
|
84
|
+
"startingheight": 467483,
|
85
|
+
"banscore": 0,
|
86
|
+
"synced_headers": 467515,
|
87
|
+
"synced_blocks": 467515,
|
88
|
+
"inflight": [
|
89
|
+
],
|
90
|
+
"whitelisted": false
|
91
|
+
}
|
92
|
+
]
|
84
93
|
HEREDOC
|
data/spec/pickynode_spec.rb
CHANGED
@@ -29,8 +29,9 @@ describe Pickynode do
|
|
29
29
|
|
30
30
|
describe '.add' do
|
31
31
|
it 'should add nodes based on user agent' do
|
32
|
-
expect(subject).to receive(:
|
33
|
-
.
|
32
|
+
expect(subject).to receive(:blockchair_snapshot)
|
33
|
+
.once
|
34
|
+
.and_return(BLOCKCHAIR_SNAPSHOT)
|
34
35
|
expect(subject).to receive(:run_cmd)
|
35
36
|
.with(%(bitcoin-cli addnode "#{ipv6_ip}" "add"))
|
36
37
|
subject.add('Satoshi')
|
@@ -40,14 +41,15 @@ describe Pickynode do
|
|
40
41
|
end
|
41
42
|
|
42
43
|
it 'should return if the filter is falsy' do
|
43
|
-
expect(subject).to_not receive(:
|
44
|
+
expect(subject).to_not receive(:blockchair_snapshot)
|
44
45
|
expect(subject).to_not receive(:run_cmd)
|
45
46
|
subject.add(false)
|
46
47
|
subject.add(nil)
|
47
48
|
end
|
48
49
|
|
49
50
|
it 'should recover gracefully if json is malformed' do
|
50
|
-
expect(subject).to receive(:
|
51
|
+
expect(subject).to receive(:blockchair_snapshot)
|
52
|
+
.once
|
51
53
|
.and_return(json_error)
|
52
54
|
expect(subject).to_not receive(:run_cmd)
|
53
55
|
subject.add('Anything')
|
@@ -62,16 +64,18 @@ describe Pickynode do
|
|
62
64
|
|
63
65
|
context 'with a limit' do
|
64
66
|
it 'should respect a limit parameter of 1' do
|
65
|
-
expect(subject).to receive(:
|
66
|
-
.
|
67
|
+
expect(subject).to receive(:blockchair_snapshot)
|
68
|
+
.once
|
69
|
+
.and_return(BLOCKCHAIR_SNAPSHOT)
|
67
70
|
expect(subject).to receive(:run_cmd)
|
68
71
|
.with('bitcoin-cli addnode "88.99.199.87:8333" "add"')
|
69
72
|
subject.add('i', 1)
|
70
73
|
end
|
71
74
|
|
72
75
|
it 'should respect a limit parameter greater than 1' do
|
73
|
-
expect(subject).to receive(:
|
74
|
-
.
|
76
|
+
expect(subject).to receive(:blockchair_snapshot)
|
77
|
+
.once
|
78
|
+
.and_return(BLOCKCHAIR_SNAPSHOT)
|
75
79
|
expect(subject).to receive(:run_cmd)
|
76
80
|
.with('bitcoin-cli addnode "88.99.199.87:8333" "add"')
|
77
81
|
expect(subject).to receive(:run_cmd)
|
@@ -84,14 +88,14 @@ describe Pickynode do
|
|
84
88
|
describe '.ban' do
|
85
89
|
it 'should ban nodes based on user agent' do
|
86
90
|
expect(subject).to receive(:`).once
|
87
|
-
|
91
|
+
.and_return(PEER_INFO)
|
88
92
|
expect(URI).to receive(:parse).with('https://131.114.88.218:33422')
|
89
|
-
|
93
|
+
.and_call_original
|
90
94
|
expect(subject).to receive(:run_cmd)
|
91
95
|
.with('bitcoin-cli setban "131.114.88.218" "add"')
|
92
96
|
subject.ban('FirstClient')
|
93
97
|
expect(URI).to receive(:parse).with("https://#{ipv6_ip}")
|
94
|
-
|
98
|
+
.and_call_original
|
95
99
|
expect(subject).to receive(:run_cmd)
|
96
100
|
.with(%(bitcoin-cli setban "#{ipv6_ip_no_port}" "add"))
|
97
101
|
subject.ban('SecondClient')
|
@@ -107,7 +111,7 @@ describe Pickynode do
|
|
107
111
|
|
108
112
|
it 'should recover gracefully if json is malformed' do
|
109
113
|
expect(subject).to receive(:`).once
|
110
|
-
|
114
|
+
.and_return(json_error)
|
111
115
|
expect(subject).to_not receive(:run_cmd)
|
112
116
|
subject.ban('Anything')
|
113
117
|
end
|
@@ -115,8 +119,9 @@ describe Pickynode do
|
|
115
119
|
|
116
120
|
describe '.connect' do
|
117
121
|
it 'should connect to nodes based on user agent' do
|
118
|
-
expect(subject).to receive(:
|
119
|
-
.
|
122
|
+
expect(subject).to receive(:blockchair_snapshot)
|
123
|
+
.once
|
124
|
+
.and_return(BLOCKCHAIR_SNAPSHOT)
|
120
125
|
expect(subject).to receive(:run_cmd)
|
121
126
|
.with('bitcoin-cli addnode "88.99.199.87:8333" "onetry"')
|
122
127
|
subject.connect('Unlimited')
|
@@ -126,15 +131,15 @@ describe Pickynode do
|
|
126
131
|
end
|
127
132
|
|
128
133
|
it 'should return if the filter is falsy' do
|
129
|
-
expect(subject).to_not receive(:
|
134
|
+
expect(subject).to_not receive(:blockchair_snapshot)
|
130
135
|
expect(subject).to_not receive(:run_cmd)
|
131
136
|
subject.connect(false)
|
132
137
|
subject.connect(nil)
|
133
138
|
end
|
134
139
|
|
135
140
|
it 'should recover gracefully if json is malformed' do
|
136
|
-
expect(subject).to receive(:
|
137
|
-
|
141
|
+
expect(subject).to receive(:blockchair_snapshot).once
|
142
|
+
.and_return(json_error)
|
138
143
|
expect(subject).to_not receive(:run_cmd)
|
139
144
|
subject.connect('Anything')
|
140
145
|
end
|
@@ -148,16 +153,18 @@ describe Pickynode do
|
|
148
153
|
|
149
154
|
context 'with a limit' do
|
150
155
|
it 'should respect a limit parameter of 1' do
|
151
|
-
expect(subject).to receive(:
|
152
|
-
.
|
156
|
+
expect(subject).to receive(:blockchair_snapshot)
|
157
|
+
.once
|
158
|
+
.and_return(BLOCKCHAIR_SNAPSHOT)
|
153
159
|
expect(subject).to receive(:run_cmd)
|
154
160
|
.with('bitcoin-cli addnode "88.99.199.87:8333" "onetry"')
|
155
161
|
subject.connect('i', 1)
|
156
162
|
end
|
157
163
|
|
158
164
|
it 'should respect a limit parameter greater than 1' do
|
159
|
-
expect(subject).to receive(:
|
160
|
-
.
|
165
|
+
expect(subject).to receive(:blockchair_snapshot)
|
166
|
+
.once
|
167
|
+
.and_return(BLOCKCHAIR_SNAPSHOT)
|
161
168
|
expect(subject).to receive(:run_cmd)
|
162
169
|
.with('bitcoin-cli addnode "88.99.199.87:8333" "onetry"')
|
163
170
|
expect(subject).to receive(:run_cmd)
|
@@ -170,7 +177,7 @@ describe Pickynode do
|
|
170
177
|
describe '.disconnect' do
|
171
178
|
it 'should disconnect nodes based on user agent' do
|
172
179
|
expect(subject).to receive(:`).once
|
173
|
-
|
180
|
+
.and_return(PEER_INFO)
|
174
181
|
expect(subject).to receive(:run_cmd)
|
175
182
|
.with(%(bitcoin-cli disconnectnode "#{ipv6_ip}"))
|
176
183
|
subject.disconnect('SecondClient')
|
@@ -188,7 +195,7 @@ describe Pickynode do
|
|
188
195
|
|
189
196
|
it 'should recover gracefully if json is malformed' do
|
190
197
|
expect(subject).to receive(:`).once
|
191
|
-
|
198
|
+
.and_return(json_error)
|
192
199
|
expect(subject).to_not receive(:run_cmd)
|
193
200
|
subject.disconnect('Anything')
|
194
201
|
end
|
@@ -197,14 +204,14 @@ describe Pickynode do
|
|
197
204
|
describe '.display' do
|
198
205
|
it 'should display connected nodes' do
|
199
206
|
expect(subject).to receive(:`).once
|
200
|
-
|
207
|
+
.and_return(PEER_INFO)
|
201
208
|
expect(subject).to receive(:ap).with(node_hash).and_return(node_hash)
|
202
209
|
expect(subject.display).to eq(node_hash)
|
203
210
|
end
|
204
211
|
|
205
212
|
it 'should recover gracefully if json is malformed' do
|
206
213
|
expect(subject).to receive(:`).once
|
207
|
-
|
214
|
+
.and_return(json_error)
|
208
215
|
expect(subject).to receive(:ap).with({}).and_return({})
|
209
216
|
expect(subject.display).to eq({})
|
210
217
|
end
|
@@ -212,16 +219,16 @@ describe Pickynode do
|
|
212
219
|
|
213
220
|
describe '.info' do
|
214
221
|
it 'should display local node info' do
|
215
|
-
expect(subject).to receive(:`).
|
216
|
-
|
222
|
+
expect(subject).to receive(:`).twice
|
223
|
+
.and_return(NODE_INFO)
|
217
224
|
expect(subject).to receive(:ap).with(parsed_node_info)
|
218
|
-
|
225
|
+
.and_return(parsed_node_info)
|
219
226
|
expect(subject.info).to eq(parsed_node_info)
|
220
227
|
end
|
221
228
|
|
222
229
|
it 'should recover gracefully if json is malformed' do
|
223
|
-
expect(subject).to receive(:`).
|
224
|
-
|
230
|
+
expect(subject).to receive(:`).twice
|
231
|
+
.and_return(json_error)
|
225
232
|
expect(subject).to receive(:ap).with({}).and_return({})
|
226
233
|
expect(subject.info).to eq({})
|
227
234
|
end
|
@@ -242,30 +249,31 @@ describe Pickynode do
|
|
242
249
|
end
|
243
250
|
|
244
251
|
it 'should call add, connect, ban, disconnect and info' do
|
245
|
-
expect(subject).to receive(:
|
246
|
-
.
|
252
|
+
expect(subject).to receive(:blockchair_snapshot)
|
253
|
+
.once
|
254
|
+
.and_return(BLOCKCHAIR_SNAPSHOT)
|
247
255
|
expect(subject).to receive(:getpeerinfo).once
|
248
|
-
|
256
|
+
.and_return(PEER_INFO)
|
249
257
|
expect(subject).to receive(:add).with(opts[:add], opts[:limit])
|
250
|
-
|
258
|
+
.and_call_original
|
251
259
|
expect(subject).to receive(:connect).with(opts[:connect], opts[:limit])
|
252
|
-
|
260
|
+
.and_call_original
|
253
261
|
expect(subject).to receive(:ban).with(opts[:ban])
|
254
|
-
|
262
|
+
.and_call_original
|
255
263
|
expect(subject).to receive(:disconnect).with(opts[:disconnect])
|
256
|
-
|
264
|
+
.and_call_original
|
257
265
|
expect(subject).to receive(:info)
|
258
266
|
expect(subject).to_not receive(:display)
|
259
267
|
subject.run
|
260
268
|
end
|
261
269
|
|
262
270
|
it 'should recover gracefully if json is malformed' do
|
263
|
-
expect(subject).to receive(:
|
264
|
-
|
271
|
+
expect(subject).to receive(:blockchair_snapshot).at_least(1)
|
272
|
+
.and_return(json_error)
|
265
273
|
expect(subject).to receive(:getpeerinfo).at_least(1)
|
266
|
-
|
267
|
-
expect(subject).to receive(:`)
|
268
|
-
|
274
|
+
.and_return(json_error)
|
275
|
+
expect(subject).to receive(:`).twice
|
276
|
+
.and_return(json_error)
|
269
277
|
expect(subject).to receive(:info)
|
270
278
|
.and_call_original
|
271
279
|
expect(subject).to receive(:ap).with({})
|
@@ -281,7 +289,7 @@ describe Pickynode do
|
|
281
289
|
|
282
290
|
it 'should call display' do
|
283
291
|
expect(subject).to receive(:`).once
|
284
|
-
|
292
|
+
.and_return(PEER_INFO)
|
285
293
|
expect(subject).to receive(:ap).with(node_hash).and_return(node_hash)
|
286
294
|
expect(subject).to receive(:display).and_call_original
|
287
295
|
subject.run
|
@@ -289,7 +297,7 @@ describe Pickynode do
|
|
289
297
|
|
290
298
|
it 'should recover gracefully if json is malformed' do
|
291
299
|
expect(subject).to receive(:`).once
|
292
|
-
|
300
|
+
.and_return(json_error)
|
293
301
|
expect(subject).to_not receive(:run_cmd)
|
294
302
|
expect(subject).to_not receive(:info)
|
295
303
|
expect(subject).to receive(:ap).with({}).and_return({})
|
@@ -299,9 +307,10 @@ describe Pickynode do
|
|
299
307
|
end
|
300
308
|
|
301
309
|
describe 'clear_cache' do
|
302
|
-
it 'should clear the
|
303
|
-
expect(subject).to receive(:
|
304
|
-
.
|
310
|
+
it 'should clear the blockchair cache' do
|
311
|
+
expect(subject).to receive(:blockchair_snapshot)
|
312
|
+
.once
|
313
|
+
.and_return(BLOCKCHAIR_SNAPSHOT)
|
305
314
|
expect(subject).to receive(:run_cmd)
|
306
315
|
.with(%(bitcoin-cli addnode "#{ipv6_ip}" "add"))
|
307
316
|
expect(subject).to receive(:run_cmd)
|
@@ -309,8 +318,9 @@ describe Pickynode do
|
|
309
318
|
subject.add('Satoshi')
|
310
319
|
subject.add('Unlimited')
|
311
320
|
subject.clear_cache
|
312
|
-
expect(subject).to receive(:
|
313
|
-
.
|
321
|
+
expect(subject).to receive(:blockchair_snapshot)
|
322
|
+
.once
|
323
|
+
.and_return(BLOCKCHAIR_SNAPSHOT)
|
314
324
|
expect(subject).to receive(:run_cmd)
|
315
325
|
.with(%(bitcoin-cli addnode "#{ipv6_ip}" "add"))
|
316
326
|
subject.add('Satoshi')
|
@@ -318,11 +328,11 @@ describe Pickynode do
|
|
318
328
|
|
319
329
|
it 'should clear the getpeerinfo cache' do
|
320
330
|
expect(subject).to receive(:getpeerinfo).once
|
321
|
-
|
331
|
+
.and_return(PEER_INFO)
|
322
332
|
expect(URI).to receive(:parse).with('https://131.114.88.218:33422')
|
323
|
-
|
333
|
+
.and_call_original
|
324
334
|
expect(URI).to receive(:parse).with(%(https://#{ipv6_ip}))
|
325
|
-
|
335
|
+
.and_call_original
|
326
336
|
expect(subject).to receive(:run_cmd)
|
327
337
|
.with('bitcoin-cli setban "131.114.88.218" "add"')
|
328
338
|
expect(subject).to receive(:run_cmd)
|
@@ -331,9 +341,9 @@ describe Pickynode do
|
|
331
341
|
subject.ban('SecondClient')
|
332
342
|
subject.clear_cache
|
333
343
|
expect(subject).to receive(:getpeerinfo).once
|
334
|
-
|
344
|
+
.and_return(PEER_INFO)
|
335
345
|
expect(URI).to receive(:parse).with('https://131.114.88.218:33422')
|
336
|
-
|
346
|
+
.and_call_original
|
337
347
|
expect(subject).to receive(:run_cmd)
|
338
348
|
.with('bitcoin-cli setban "131.114.88.218" "add"')
|
339
349
|
subject.ban('FirstClient')
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pickynode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Ellithorpe
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|
@@ -25,33 +25,47 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.7'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: base64
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '2
|
33
|
+
version: '0.2'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '2
|
40
|
+
version: '0.2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: optimist
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
48
|
-
type: :
|
47
|
+
version: '3.0'
|
48
|
+
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3.
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: ostruct
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.6'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.6'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +80,20 @@ dependencies:
|
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '12.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.6'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.6'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
98
|
name: rubocop
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -107,7 +135,6 @@ files:
|
|
107
135
|
- ".ruby-version"
|
108
136
|
- ".travis.yml"
|
109
137
|
- Gemfile
|
110
|
-
- Gemfile.lock
|
111
138
|
- LICENSE
|
112
139
|
- README.md
|
113
140
|
- Rakefile
|
@@ -122,7 +149,7 @@ homepage: http://github.com/zquestz/pickynode
|
|
122
149
|
licenses:
|
123
150
|
- MIT
|
124
151
|
metadata: {}
|
125
|
-
post_install_message:
|
152
|
+
post_install_message:
|
126
153
|
rdoc_options: []
|
127
154
|
require_paths:
|
128
155
|
- lib
|
@@ -130,16 +157,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
130
157
|
requirements:
|
131
158
|
- - ">="
|
132
159
|
- !ruby/object:Gem::Version
|
133
|
-
version: '2.
|
160
|
+
version: '2.5'
|
134
161
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
162
|
requirements:
|
136
163
|
- - ">="
|
137
164
|
- !ruby/object:Gem::Version
|
138
165
|
version: '0'
|
139
166
|
requirements: []
|
140
|
-
|
141
|
-
|
142
|
-
signing_key:
|
167
|
+
rubygems_version: 3.0.9
|
168
|
+
signing_key:
|
143
169
|
specification_version: 4
|
144
170
|
summary: Manage connections to your bitcoin node
|
145
171
|
test_files: []
|
data/Gemfile.lock
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
GEM
|
2
|
-
remote: https://rubygems.org/
|
3
|
-
specs:
|
4
|
-
ast (2.3.0)
|
5
|
-
awesome_print (1.7.0)
|
6
|
-
diff-lcs (1.3)
|
7
|
-
docile (1.1.5)
|
8
|
-
json (2.1.0)
|
9
|
-
parser (2.4.0.0)
|
10
|
-
ast (~> 2.2)
|
11
|
-
powerpack (0.1.1)
|
12
|
-
rainbow (2.2.2)
|
13
|
-
rake
|
14
|
-
rake (12.0.0)
|
15
|
-
rspec (3.6.0)
|
16
|
-
rspec-core (~> 3.6.0)
|
17
|
-
rspec-expectations (~> 3.6.0)
|
18
|
-
rspec-mocks (~> 3.6.0)
|
19
|
-
rspec-core (3.6.0)
|
20
|
-
rspec-support (~> 3.6.0)
|
21
|
-
rspec-expectations (3.6.0)
|
22
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
23
|
-
rspec-support (~> 3.6.0)
|
24
|
-
rspec-mocks (3.6.0)
|
25
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
26
|
-
rspec-support (~> 3.6.0)
|
27
|
-
rspec-support (3.6.0)
|
28
|
-
rubocop (0.48.1)
|
29
|
-
parser (>= 2.3.3.1, < 3.0)
|
30
|
-
powerpack (~> 0.1)
|
31
|
-
rainbow (>= 1.99.1, < 3.0)
|
32
|
-
ruby-progressbar (~> 1.7)
|
33
|
-
unicode-display_width (~> 1.0, >= 1.0.1)
|
34
|
-
ruby-progressbar (1.8.1)
|
35
|
-
simplecov (0.14.1)
|
36
|
-
docile (~> 1.1.0)
|
37
|
-
json (>= 1.8, < 3)
|
38
|
-
simplecov-html (~> 0.10.0)
|
39
|
-
simplecov-html (0.10.1)
|
40
|
-
trollop (2.1.2)
|
41
|
-
unicode-display_width (1.2.1)
|
42
|
-
|
43
|
-
PLATFORMS
|
44
|
-
ruby
|
45
|
-
|
46
|
-
DEPENDENCIES
|
47
|
-
awesome_print (~> 1.7)
|
48
|
-
rake (~> 12.0)
|
49
|
-
rspec (~> 3.6)
|
50
|
-
rubocop (~> 0.48)
|
51
|
-
simplecov (~> 0.14)
|
52
|
-
trollop (~> 2.1)
|
53
|
-
|
54
|
-
RUBY VERSION
|
55
|
-
ruby 2.3.4p301
|
56
|
-
|
57
|
-
BUNDLED WITH
|
58
|
-
1.14.6
|