Skip to content

Instantly share code, notes, and snippets.

@inertia186
Last active August 1, 2022 18:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save inertia186/d57c9bc744f05ada01d173521c01df8a to your computer and use it in GitHub Desktop.
Save inertia186/d57c9bc744f05ada01d173521c01df8a to your computer and use it in GitHub Desktop.
Dr. Doogie (`drdoogie.rb`) is a voting trail bot. See: https://hive.blog/radiator/@inertia/drdoogie-rb-vote-trail-script
This is the Dr. Doogie bot for STEEM and GOLOS. Please have a look at the README.md file.
drdoogie.log
  • Title: drdoogie.rb - Vote Trail Bot for Hive
  • Tags: radiator ruby curation
  • Notes:

Fixes

Added support for Hive.

Features

  • YAML config.
    • global
      • mode
        • head - the last block
        • irreversible - (default) the block that is confirmed by 2/3 of all block producers and is thus irreversible!
    • scale_votes - scale votes in %
    • max_age - only vote if the post is under this number in minutes
    • allow_upvote - trail upvotes
    • allow_downvote - trail downvotes
    • enable_comments - vote for comments
    • skip_tags - do not vote if the post contains any of these tags
    • only_tags - only vote if the post includes at least one of these tags

Overview

Dr. Doogie (drdoogie.rb) is a voting bot that will trail the votes of other accounts in order to then mirror their voting pattern.


Install

To use this Radiator script:

Get rvm

See: rvm.io

Get bundler
$ gem install bundler
Bundle

First, clone this gist and install the dependencies:

$ git clone https://gist.github.com/d57c9bc744f05ada01d173521c01df8a.git drdoogie
$ cd drdoogie
$ bundle install
Run
$ ruby drdoogie.rb

Check here to see an updated version of this script:

https://gist.github.com/inertia186/d57c9bc744f05ada01d173521c01df8a


Upgrade

Typically, you can upgrade to the latest version by this command, from the original directory you cloned into:

$ git pull

Usually, this works fine as long as you haven't modified anything. If you get an error, try this:

$ git stash --all
$ git pull --rebase
$ git stash pop

If you're still having problems, I suggest starting a new clone.


Troubleshooting

Problem: What does this error mean?
drdoogie.yml:1: syntax error, unexpected ':', expecting end-of-input
Solution: You ran ruby drdoogie.yml but you should run ruby drdoogie.rb.

Problem: Everything looks ok, but every time drdoogie tries to post, I get this error:
`from_base58': Invalid version (RuntimeError)
Solution: You're trying to vote with an invalid key.

Make sure the .yml file voters item have the correct account name and WIF posting key.

Problem: The node I'm using is down.

Is there a list of nodes?

Solution: Yes:

https://developers.hive.io/quickstart/#quickstart-hive-full-nodes


See my previous Ruby How To posts in: #radiator #ruby

Get in touch!

If you're using drdoogie, I'd love to hear from you. Drop me a line and tell me what you think! I'm @inertia on Hive.

License

I don't believe in intellectual "property". If you do, consider drdoogie as licensed under a Creative Commons CC0 License.

require 'rubygems'
require 'bundler/setup'
require 'yaml'
require 'pry'
Bundler.require
defined? Thread.report_on_exception and Thread.report_on_exception = true
# If there are problems, this is the most time we'll wait (in seconds).
MAX_BACKOFF = 12.8
@config_path = __FILE__.sub(/\.rb$/, '.yml')
unless File.exist? @config_path
puts "Unable to find: #{@config_path}"
exit
end
@config = YAML.load_file(@config_path)
chain = case @config[:chain_options][:chain].to_sym
when :steem then :steem
when :hive
_chain_options = {
chain: :hive,
url: @config[:chain_options][:url],
failover_urls: [@config[:chain_options][:url]]
}
Radiator::Api.new(_chain_options).get_accounts(['fullnodeupdate']) do |accounts|
metadata = JSON[accounts[0].json_metadata] rescue {}
failover_urls = metadata.fetch('report').map{|n| n['node'] if !!n.fetch('hive')}.compact
@config[:chain_options][:failover_urls] = failover_urls - [@config[:chain_options][:url]]
end
:hive
when :golos then :golos
else
abort("Unknown chain: #{chain}")
end
@options = {
chain: chain,
url: @config[:chain_options][:url],
logger: Logger.new(__FILE__.sub(/\.rb$/, '.log'))
}
if !!@config[:chain_options][:failover_urls] && @config[:chain_options][:failover_urls].any?
@options[:failover_urls] = @config[:chain_options][:failover_urls]
end
def may_vote?(op)
@config[:trails].keys.map(&:to_s).include? op.voter
end
def vote(trailing_vote, comment)
age = (Time.now - Time.parse(comment.created + 'Z')).to_i / 60
reply = comment.parent_author != ''
metadata = JSON[comment.json_metadata] rescue {}
tags = [metadata['tags']].flatten.compact
upvote = trailing_vote.weight > 0
downvote = trailing_vote.weight < 0
unvote = trailing_vote.weight == 0
@config[:trails].each do |trail, options|
next unless age <= options[:max_age]
next if reply && !options[:enable_comments]
next if upvote && !options[:allow_upvote]
next if downvote && !options[:allow_downvote]
next if !!options[:skip_tags] && (options[:skip_tags] & tags).any?
next if !!options[:only_tags] && (options[:only_tags] & tags).any?
puts "#{trailing_vote.voter} voted for #{trailing_vote.author}/#{trailing_vote.permlink} at #{trailing_vote.weight / 100.0} %"
scale = options[:scale_votes].to_f / 100
weight = (trailing_vote.weight * scale).to_i
@config[:voters].each do |voter|
name, wif = voter.split(' ')
next if comment.active_votes.map(&:voter).include? name
op = {
type: :vote,
voter: name,
author: trailing_vote.author,
permlink: trailing_vote.permlink,
weight: weight
}
tx = Radiator::Transaction.new(@options.merge(wif: wif))
tx.operations << op
puts tx.process(true)
end
end
end
puts "Now trailing #{@config[:trails].keys.join(', ')} ..."
loop do
@api = Radiator::Api.new(@options)
@stream = Radiator::Stream.new(@options)
mode = @config[:global][:mode].to_sym rescue :irreversible
begin
@stream.operations(:vote, nil, mode) do |op|
@backoff ||= 0.001
next unless may_vote?(op)
response = @api.get_content(op.author, op.permlink)
comment = response.result
Thread.new do
vote(op, comment)
end
@backoff = nil
end
rescue => e
m = e.message
if m =~ /undefined method `transactions' for nil:NilClass/ && mode == :head
# Block hasn't reached the node yet. Just retry with a small delay
# without reporting an error.
sleep 0.2
else
puts "Pausing #{@backoff} :: Unable to stream on current node. Error: #{e}"
sleep @backoff
@backoff = [@backoff * 2, MAX_BACKOFF].min
end
end
end
:voters:
- social 5JrvPrQeBBvCRdjv29iDvkwn3EQYZ9jqfAHzrCyUvfbEbRkrYFC
:global:
# Note, if you're playing the curation game, you'll probably want to use head
# mode. This will usually cast your votes sooner.
#
# mode: head - the last block
# mode: irreversible - the block that is confirmed by 2/3 of all block
# producers and is thus irreversible!
:mode: irreversible
:trails:
:banjo:
:scale_votes: 100.00 %
:max_age: 1440
:allow_upvote: true
:allow_downvote: true
:enable_comments: true
:skip_tags:
- nsfw
- test
# :only_tags:
# - steemit
:chain_options:
:chain: hive
:url: https://api.openhive.network
source 'https://rubygems.org'
gem 'radiator', '0.4.9'
gem 'pry'
GEM
remote: https://rubygems.org/
specs:
awesome_print (1.9.2)
base58 (0.2.3)
bindata (2.4.10)
bitcoin-ruby (0.0.20)
eventmachine
ffi
scrypt
coderay (1.1.3)
connection_pool (2.2.5)
eventmachine (1.2.7)
ffi (1.15.5)
ffi-compiler (1.0.1)
ffi (>= 1.0.0)
rake
hashie (5.0.0)
hive-ruby (1.0.4)
base58 (~> 0.2, >= 0.2.3)
bindata (~> 2.4, >= 2.4.4)
bitcoin-ruby (~> 0.0, = 0.0.20)
ffi (~> 1.9, >= 1.9.23)
hashie (>= 3.5)
json (~> 2.1, >= 2.1.0)
logging (~> 2.2, >= 2.2.0)
json (2.6.2)
little-plugger (1.1.4)
logging (2.3.1)
little-plugger (~> 1.1)
multi_json (~> 1.14)
method_source (1.0.0)
multi_json (1.15.0)
net-http-persistent (4.0.1)
connection_pool (~> 2.2)
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
radiator (0.4.9)
awesome_print (~> 1.7, >= 1.7.0)
bitcoin-ruby (= 0.0.20)
ffi (~> 1.9, >= 1.9.18)
hashie (>= 3.5)
hive-ruby (~> 1.0, >= 1.0.3)
json (~> 2.0, >= 2.0.2)
logging (~> 2.2, >= 2.2.0)
net-http-persistent (>= 2.5.2)
steem-ruby (~> 0.9, >= 0.9.7)
rake (13.0.6)
scrypt (3.0.7)
ffi-compiler (>= 1.0, < 2.0)
steem-ruby (0.9.8)
base58 (~> 0.2, >= 0.2.3)
bindata (~> 2.4, >= 2.4.4)
bitcoin-ruby (~> 0.0, >= 0.0.18)
ffi (~> 1.9, >= 1.9.23)
hashie (~> 5.0, >= 4.1.0)
json (~> 2.1, >= 2.1.0)
logging (~> 2.2, >= 2.2.0)
PLATFORMS
ruby
DEPENDENCIES
pry
radiator (= 0.4.9)
BUNDLED WITH
2.3.19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment