Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Dr. Doogie (`drdoogie.rb`) is a voting trail bot. See: https://steemit.com/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
  • Tags: radiator ruby steem steemdev curation
  • Notes:

Fixes

  • Added exponential back-off for errors.
  • When handling blocks in mode: head, just retrying without reporting an error.

New Features

  • global
    • mode
      • head - the last block
      • irreversible - (default) the block that is confirmed by 2/3 of all block producers and is thus irreversible!

Features

  • YAML config.
    • 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:

Linux
$ sudo apt-get install ruby-full git openssl libssl1.0.0 libssl-dev
$ gem install bundler
macOS
$ gem install bundler

I've tested it on various versions of ruby. The oldest one I got it to work was:

ruby 2.0.0p645 (2015-04-13 revision 50299) [x86_64-darwin14.4.0]

First, clone this gist and install the dependencies:

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

Then run it:

$ 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, special thanks to @ripplerm.

https://ripplerm.github.io/steem-servers/


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 STEEM and SteemSpeak.

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)
@options = {
chain: @config[:chain_options][:chain].to_sym,
url: @config[:chain_options][:url],
logger: Logger.new(__FILE__.sub(/\.rb$/, '.log'))
}
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 != ''
tags = JSON[comment.json_metadata]['tags']
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] & 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: steem
:url: https://api.steemit.com
source 'https://rubygems.org'
gem 'radiator'
gem 'pry'
GEM
remote: https://rubygems.org/
specs:
awesome_print (1.8.0)
bitcoin-ruby (0.0.18)
coderay (1.1.2)
connection_pool (2.2.1)
ffi (1.9.23)
hashie (3.5.7)
json (2.1.0)
little-plugger (1.1.4)
logging (2.2.2)
little-plugger (~> 1.1)
multi_json (~> 1.10)
method_source (0.9.0)
multi_json (1.13.1)
net-http-persistent (3.0.0)
connection_pool (~> 2.2)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
radiator (0.4.1)
awesome_print (~> 1.7, >= 1.7.0)
bitcoin-ruby (~> 0.0, >= 0.0.11)
ffi (~> 1.9, >= 1.9.18)
hashie (~> 3.5, >= 3.5.5)
json (~> 2.0, >= 2.0.2)
logging (~> 2.2, >= 2.2.0)
net-http-persistent (>= 2.5.2)
PLATFORMS
ruby
DEPENDENCIES
pry
radiator
BUNDLED WITH
1.16.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.