Digging into Hive ruby library

in Programming & Dev3 years ago

I wanted to create a little script to automate the reward claiming for my account.

I know there is the amazing hive.autoclaim service, but I wanted to learn a bit more how Hive was working and thought it would be an easy task to begin with.

I couldn’t be more wrong.

First thing first, I visited the hive developer documentation.
It looks like there is 3 supported languages, javascript, python and ruby so I decided to pick Ruby which is the one I most familiar with.

Picture by Joshua Fuller

There is no examples in the tutorial section for claiming rewards with Ruby but the Javascript library has an example.

So I need two operations, the first one get_accounts to have the actual rewards and the second one is claim_reward_balance, to make the claim itself.

Let’s look at Radiator source code now!

EDITOR=code bundle open radiator

Ok, I have a find_account method and a claim_reward_balance method, perfect.

I thought I found everything I needed at this point and the Radiator code is readable and heavily commented, so let’s go.

At this point my implementation looked like this:

# frozen_string_literal: true

require 'rubygems'
require 'bundler/setup'

Bundler.require

ACCOUNT_NAME = 'tipy'
OPTIONS = {
  chain: :hive,
  wif: '5J*****************'
}.freeze

def pending_rewards
  chain = Radiator::Chain.new(OPTIONS)
  account_data = chain.find_account(ACCOUNT_NAME)

  account_data.slice(
    :reward_hive_balance,
    :reward_hbd_balance,
    :reward_vesting_balance
  )
end

def claim_rewards(rewards)
  chain = Radiator::Chain.new(OPTIONS.merge(account_name: ACCOUNT_NAME))
  chain.claim_reward_balance!(
    reward_hive: rewards.reward_hive_balance,
    reward_hbd: rewards.reward_hbd_balance,
    reward_vests: rewards.reward_vesting_balance
  )
end

def empty_reward?(rewards)
  rewards.reward_hive_balance == '0.000 HIVE' && rewards.reward_hbd_balance == '0.000 HBD' && rewards.reward_vesting_balance == '0.000000 VESTS'
end

pr = pending_rewards
if empty_reward?(pr)
  puts 'Nothing to claim'
  return
end

puts "Rewards: #{pr.to_h}"
output = claim_rewards(pr)
puts output

and it was not working… :(

The code for making the claim_reward operation was throwing this exception:

{“error":"condenser_api.broadcast_transaction_synchronous: Assert Exception:is_asset_type( reward_hbd, HBD_SYMBOL ): Reward HBD must be expressed in HBD"} (Hive::UnexpectedAssetError)

Let’s look at the Radiator code:

# Create a claim_reward_balance operation.
#
# Examples:
#
#     steem = Radiator::Chain.new(chain: :steem, account_name: 'your account name', wif: 'your wif')
#     steem.claim_reward_balance(reward_sbd: '100.000 SBD')
#     steem.broadcast!
#
# @param options [::Hash] options
# @option options [String] :reward_steem The amount of STEEM to claim, like: `100.000 STEEM`
# @option options [String] :reward_sbd The amount of SBD to claim, like: `100.000 SBD`
# @option options [String] :reward_vests The amount of VESTS to claim, like: `100.000000 VESTS`
def claim_reward_balance(options)
    reward_steem = options[:reward_steem] || '0.000 STEEM'
    reward_sbd = options[:reward_sbd] || '0.000 SBD'
    reward_vests = options[:reward_vests] || '0.000000 VESTS'

    @operations << {
        type: :claim_reward_balance,
        account: account_name,
        reward_steem: reward_steem,
        reward_sbd: reward_sbd,
        reward_vests: reward_vests
    }

    self
end

Obviously, it cannot work, this piece of code only works for Steem (Radiator is an “high level” library which works for both Hive and Steem).

But this method is just a kind of wrapper to create a Transaction, so I switched to transaction

def claim_rewards(rewards)
  tx = Radiator::Transaction.new(OPTIONS)
  tx.operations << {
    type: :claim_reward_balance,
    account: ACCOUNT_NAME,
    reward_hive: rewards.reward_hive_balance,
    reward_hbd: rewards.reward_hbd_balance,
    reward_vests: rewards.reward_vesting_balance
  }

  tx.process(true)
end

and it’s still not working, but I made some progress, I’ve got an new error now:

{"error":"condenser_api.broadcast_transaction_synchronous: missing required posting authority:Missing Posting Authority tipy"} (Hive::MissingPostingAuthorityError)

WTF is this error? I have to admit I was a bit lost at this point so I asked for help on Discord.

I thought my WIF key was wrong and I tried every Hive keys without any success, but the good point is I now have a clear understanding of the WIF format.

I tried the code from the Javascript tutorial and my WIF key was the right one.

So I tried to see if there were an issue with the Radiator code. I’m pretty sure there is one but I don’t know why.

To be sure, the problem was in the Radiator code, I switched to hive-ruby (the library underneath Radiator):

def claim_rewards(rewards)
  options = OPTIONS.merge(params: {
                            account: ACCOUNT_NAME,
                            reward_hive: rewards.reward_hive_balance,
                            reward_hbd: rewards.reward_hbd_balance,
                            reward_vests: rewards.reward_vesting_balance
                          })

  Hive::Broadcast.claim_reward_balance(options)
end

and it’s now working!


At some points, I was really close to give up and move to Javascript, but instead I decided to explore the Radiator library, and I’m really glad I did.

I learnt a lot about the library itself, and Hive internals.

I don’t want to blame anyone with this post, just share my experience.
Thanks inertia for maintaining the Radiator and hive-ruby librairies, I browsed the code enough to say it’s a great job.

Maybe I’ll try to understand the Radiator code more and try to do some pull requests (but hey opensource depends on good will and it’s finally sunny here ;p).

I’ve seen some vcr tests in the code and this is something I wanted to try myself for a long time, so this is maybe the right time to do it.

The ruby documentation on Hive developer portal also needs some love.

Hope you enjoyed my little adventure writing this piece of code.

Happy coding!

Sort:  

I know java, python, R also, but I don't know about Ruby.
Feeling stupid now.....
Great post by the way 👍

Congratulations @tipy! You have completed the following achievement on the Hive blockchain and have been rewarded with new badge(s) :

You received more than 50 upvotes.
Your next target is to reach 100 upvotes.

You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP

Yay! 🤗
Your content has been boosted with Ecency Points, by @tipy.
Use Ecency daily to boost your growth on platform!

Support Ecency
Vote for Proposal
Delegate HP and earn more

Bonjour et merci de votre vote

I’m not sure why you had trouble with Radiator. But maybe there was a bug 3 years ago. I went back to my original tutorial app to see if it still worked. I also updated it to use Hive examples:

https://peakd.com/@inertia/stinkypete-rb-reward-claim-script-for-steem

Yes, the devportal should also have a simplified tutorial for this. I should work on that.