Building a Reliable Witness Vote Checker for the Steem Blockchain (with Retry & Exponential Backoff)


When working with decentralized platforms like Steem, it’s important to expect occasional hiccups — network issues, API rate limits, or temporary downtimes. That’s why any integration, bot, or tool you build should be able to fail gracefully and recover smartly.

In this post, I’ll walk you through a simple yet robust vote-checking utility for the Steem blockchain that:

First Version: Check a Witness voted by

Here’s a handy Node.js function that checks if a Steem user has voted for a specific witness — either directly or via a proxy.

function is_voted_by(witness, id) {
    return new Promise((resolve, reject) => {
        steem.api.getAccounts([id], function(err, response) {
            if (err) reject(err);
            if (typeof response == "undefined") reject("undefined");
            const data = response[0];
            resolve((data.proxy === witness) || data.witness_votes.includes(witness)); 
        });          
    });
}

It fetches the account data for the given id. Then it checks if the user has set a voting proxy matching the target witness, or if the witness is in their direct vote list.

Retry-Enabled Witness Vote Checker for Steem

Here’s the updated version of the function with a simple retry mechanism (up to 3 attempts with a 1-second delay between retries). Here’s a more robust version of the vote check function with retry logic built-in:

function is_voted_by(witness, id, retries = 3) {
    return new Promise((resolve, reject) => {
        const attempt = (remaining) => {
            steem.api.getAccounts([id], function(err, response) {
                if (err || typeof response === "undefined") {
                    if (remaining > 0) {
                        setTimeout(() => attempt(remaining - 1), 1000); // Retry after 1 second
                    } else {
                        reject(err || "undefined response");
                    }
                    return;
                }
                const data = response[0];
                resolve((data.proxy === witness) || data.witness_votes.includes(witness)); 
            });
        };
        attempt(retries);
    });
}

This version implements up to 3 retries if the Steem API fails or returns undefined. It helps handle unreliable network conditions or temporary API hiccups. Same functionality: checks direct witness votes or proxy delegation.

Retry exponential backoff

Uses exponential backoff to avoid hammering the API and log each attempt for better debugging and visibility.

module.exports.is_voted_by = function(witness, id, retries = 3, delay = 1000) {
    return new Promise((resolve, reject) => {
        const attempt = (remaining, currentDelay) => {
            console.log(`Checking vote for "${id}" against witness "${witness}"... (${retries - remaining + 1}/${retries})`);

            steem.api.getAccounts([id], function(err, response) {
                if (err || typeof response === "undefined") {
                    console.warn(`Attempt failed: ${err || 'undefined response'}`);
                    
                    if (remaining > 0) {
                        console.log(`Retrying in ${currentDelay}ms...`);
                        setTimeout(() => attempt(remaining - 1, currentDelay * 2), currentDelay); // Exponential backoff
                    } else {
                        reject(err || "undefined response after retries");
                    }
                    return;
                }

                const data = response[0];
                const voted = (data.proxy === witness) || data.witness_votes.includes(witness);
                console.log(`Vote check result: ${voted}`);
                resolve(voted);
            });
        };

        attempt(retries, delay);
    });
};

This:

  • Calls the Steem API to get account info for a given id.
  • Checks if the user voted for a specific witness, either: Directly (i.e., in witness_votes), or Indirectly via a proxy (i.e., if proxy === witness).

If the API call fails or returns undefined, it: Waits, Retries (up to retries times), And increases the wait time exponentially (1s, 2s, 4s, etc.).

🔧 Why Use Exponential Backoff?

Exponential backoff is a classic strategy in network programming — if a service is down or struggling, hitting it again quickly is more likely to make things worse. Slowing down between retries gives the system time to recover, and is kinder to APIs.

🧪 Example Usage
is_voted_by('witness-name', 'username')
    .then(voted => {
        if (voted) {
            console.log("User supports the witness!");
        } else {
            console.log("User has not voted for the witness.");
        }
    })
    .catch(err => {
        console.error("Error checking vote:", err);
    });

🏁 Final Thoughts

When building tools that interact with blockchains, resilience is key. A little retry logic can go a long way in keeping your apps functional and user-friendly — even when the underlying infrastructure hits a rough patch.

Steem Programming

–EOF (The Ultimate Computing & Technology Blog) —

776 words
Last Post: AI Transforms Photos into Ghibli Style? ChatGPT-4o Costs Money, But Here's a Free Method!
Next Post: Teaching Kids Programming - Compute the Range Sum with Update: A Deep Dive into Segment Tree, SQRT Decomposition, Brute Force & Prefix Sum

The Permanent URL is: Building a Reliable Witness Vote Checker for the Steem Blockchain (with Retry & Exponential Backoff) (AMP Version)

Leave a Reply